Swift-语言学习


import UIKit //如果是ios程序则导入UIKit
//import Cocoa //如果是osX程序则导入Cocoa
var greeting = "Hello, playground"
print(greeting)
//不要求每行语句结束的时候需要分号,但是当一行需要写多个语句时需要分号
//1.对标识符的要求:区分大小写,标识符可以是数字下划线字母,开头不能是数字
//2.swift使用的是unicode编码 包含了多种语言和表情符号
//3.关键字作为标识符时需要在关键字前后加上重音符号``
let `class` = "zx"
//4.空格要求,没有python要求严格 但是也是有一定要求的,推荐写法
var a = 1 + 2
//5.用print打印输出,如果不要换行输出将最后一个参数赋值为空字符串即可
print("\(a)",terminator: "")
//6.用readline来接受用户输入
let input = readLine()
//7.let定义常量(不可修改) var定义变量(可修改) swift可自动识别属性类别
//8.Int UInt(无符号整数) Float Double Bool String Character optional(可选类型,处理有值或者无值情况) tyealias(变量别名类型)
//9.print输出变量时用括号和反斜线来插入变量
print("\(a)")
//10.optionals类型详解:任何类型?表示不知道当前是否有值,无论有没有值都不会报错 无值相当于nil;任何类型!表示强制解析,即知道当前有值可解析;可选绑定,可用于if和while中对可选类型的值进行判断然后把值赋给一个常量或变量
//11.类型标注 可对变量声明是什么类型的变量
let b:Float = 3.41
print(b)
//12.swift中用+=代替++ -=代替--
//闭区间用a...b表示 半开区间用a..//13.循环语句:repeat while 循环与while语句的区别在于他会先执行之前repeat中的代码块在继续向下执行
//14.循环控制语句 fallthrough语句在case的情况下使用,用来贯穿两个case,同时在fallthrough之后紧跟的case条件中不能定义变量
//15 字符串有String的实例化 和直接赋值两种方式
var A = "20"
var B = String("30")
var C = "\(A)aaaa\(B)"//字符串插入 类似于print输出
print(C)
//16 字符串可以用+来连接,长度用count函数输出 ==来比较字符串是否相等
//17 一些比较特殊的字符串函数
B.hasPrefix("2")//判断是否存在特定前缀
B.hasSuffix("0")//判断是否存在特定后缀
Int(B)//将字符串转化为Int
//18 Swift的String 类型是基于 Unicode建立的。可以使用utf8和utf16来输出对应的UTF-8 与 UTF-16 的编码
//19 单字符
let char1:Character = "A"  //单字符的赋值方式
for ch in "zx"{   //单字符的输出
    print(ch)
}
//20 数组的基本使用
var arrayA = [10,20,30] //数组的第一种定义方式
var arrayB = [Int](repeating: 1, count: 3) //第二种定义方式 数量为3,初始值为1的数组
arrayB[1] = 2//可以通过下标访问
var arrayC = arrayA + arrayB //可以通过+来直接合并数组
for item in arrayC{
    print(item) // 数组元素的输出
}
for(index,item) in arrayC.enumerated(){
    print("\(index),\(item)") //也可以将索引和下标都输出
}
print("\(arrayC.count)")  //输出数组的元素个数 这里是6哦
//21 字典的使用
var dict:[Int:String] = [1:"one",2:"two",3:"three"] //字典定义
var newval = dict.updateValue("oneNew", forKey: 1) //按照索引来找字典对,更新val值
print("\(newval)")//输出的是optional类型
dict[2] = "twoNew"//字典可以直接通过索引访问
print("\(dict[2])")//输出的是optional类型
var remove = dict.removeValue(forKey: 2)//移除key-value
for(key,value) in dict{
    print("\(key)-\(value)")//输出key-value值
}
for(key,value) in dict.enumerated(){
    print("\(key)--\(value)")//通过索引输出
}
let dictKey = [Int](dict.keys)//将key转化为数组
let dictValue = [String](dict.values)//将value转化为数组
//22 函数使用func定义
func test(a:Int) -> Int{  //()里是形参,->是返回值 两者可以为空
    return 1;
}
func minMax(array:[Int]) -> (min:Int ,max:Int){//返回值可以为多个值,swift中叫元组,
    return(1,2)
}
func vari(members:N...){ //N...是可变参数,可接受零个值或者多个值,可变参数在变量类型后面加...的方式来定义
    for i in members{
        print(i)
    }
}
func change(a:inout Int,b:inout Int){ //一般参数的传递都是常量传递不会改变其值,但是如果要改变的话就需要用inout来声明一下类型
    let temp = a;
    a = b;
    b = temp
}
var x = 1;
var y = 2;
change(a: &x, b: &y)
//参数传递一般都是值传递即副本传递,不会影响传入值,但是如果需要改变传入值的话就需要加&来表示值可以被函数改变
//23 闭包
//闭包是自包含的功能代码块,可以在代码中使用或用来作为参数传值
//闭包的形式可分为三类:1 全局函数(有名字但是不能拿到任何值)2 嵌套函数(有名字,可以拿到封闭函数中的值)3 闭包表达式 (没有名字,根据上下文拿到值)
//全局函数:
let stuName = { print("全局函数")}
stuName();
//嵌套函数
let divide = {(val1:Int , val2:Int) -> Int in
    return val1/val2;
}
let result = divide(200,20)
print(result)
//闭包函数
let sort  = ["A" ,"T","B"]
func backwards(s1:String , s2:String) ->Bool {
    return s1 > s2
}
var reversed1 = sort.sorted(by: backwards) //闭包函数
print(reversed1)

var reversed2 = sort.sorted(by: {$0 > $1})  //参数名称简写
print(reversed2)

var reversed3 = sort.sorted(by:>)  //运算符直接写
print(reversed3)

//尾随闭包 是指在书写函数符号之后的闭包表达式,这个表达式可作为最后一个参数调用
var reversed4 = sort.sorted() {$0 > $1}  //运算符直接写
print(reversed4)

//闭包捕获值 指闭包可以在其定义的上下文中捕获常量或变量,即使定义这些常量的和变量的原域已经不存在
func makeIncrementor(forIncrement amount : Int) -> () -> Int{
    var total = 0;
    func incrementor() ->Int{//incrementor函数没有参数值却可以拿到amount
        total += amount
        return total
    }
    return incrementor
}
//闭包是引用类型 如果将闭包赋值给两个不同的常量,两个值指向的也是同一闭包
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()//10
incrementByTen()//20


//24 swift枚举 用enum来表示枚举
enum day{
    case sunday
    case monday
}
//25 swift结构体 他不需要实现文件和接口,可以允许我们创建单一文件且系统会自动生成其他代码的外部接口
struct mark{
    var mark1 = 1
    var mark2 = 2
}
let m = mark()
print("\(m.mark1)")//结构体的访问
//26 swift类
class student{
    var s = 100
}
let class1 = student()
print("\(class1.s)")
//27 ==与===
class SampleClass{
    let myProperty: String  //类成员
    init(s: String) { //init是实例化构造器
        myProperty = s
    }
}
let spClass1 = SampleClass(s: "Hello")
let spClass2 = SampleClass(s: "Hello")
if spClass1 === spClass2 {// false 如果两个常量或者变量引用同一个类实例则返回 true
    print("引用相同的类实例 \(spClass1)")
}

if spClass1 !== spClass2 {// true 如果两个常量或者变量引用不同一个类实例则返回 true
    print("引用不相同的类实例 \(spClass2)")
}
//27 swift属性
//延迟存储属性(lazy) 第一次调用的时候才会计算初始值的属性
class sample{
    lazy var no = number()//延迟存储属性需要声明为变量且使用var关键字
}
class number{
    var name = "lazy"
}
var firstSample = sample()
print(firstSample.no.name)
//实例化变量
//计算属性:getter获取值 setter设置值
//只读属性 getter获取值 没有setter
//willSet(设置新的值之前调用)和 didSet(在新的值被设置后调用)观察器来观察属性的变化
//类型属性的访问通过.来进行,但是类型属性是通过类型本身来获取和修改的 而不是通过实例话对象
//类型属性:类型属性作为类型定义一部分写在类型最外层的花括号({})内 使用关键字static来定义值类型的类型属性,
//关键字class来为类定义类型属性
struct StudMarks{
    static var totalCount = 0;
    static var markCount = 97;
}
//28 swift中的方法 swift中的方法不仅可以在类中定义(OC的方法只能在类内定义) 还可以在自己创建的类型中定义
//swift方法中默认第一个参数为局部参数名称,第二个以及后续参数为全局参数名称,除此之外,也可以为自己局部参数添加一个外部名称作为外部参数使用
class multiplication{
    var count:Int = 0
    func incrementBy(first no1 :Int , no2:Int){
        count = no1 * no2
    }
}
let counter = multiplication();
counter.incrementBy(first :10 ,no2: 10)
//类型的每个实例都有一个self属性,可以在实例方法中用self来引用当前实例
//在实例方法中修改值类型可以使用mutaing这个方法来实现(一般来说在方法中是不允许修改其值的)
struct area{
    var length = 1
    var breadth = 1
    func area()->Int{
        return length * breadth;
    }
    mutating func scaleBy(res : Int){
        length *= res
        breadth *= res
        self.length = 10;//在可变方法中可以赋给self一个全新的实例
        self.breadth = 20;
    }
}
//在类中 被类的实例调用的方法方法叫实例方法 被类型本身调用的方法叫类型方法
//29 swift的下标
//数组用array【index】定义
//字典用dictionary【key】定义
//另外 类中也可以使用subscript关键字来实现下标方法
//subscript还可以进行函数的重载
struct subexemple{
    let decrementer:Int
    subscript(index : Int) -> Int{//下标声明
        return decrementer/index
    }
}
let division = subexemple(decrementer: 100)
print(division[2])//下标实现
//30 继承 即类似C++中的父类与子类
//   重写:子类通过继承父类的方法和属性 要访问父类中的方法时可以用super前缀来访问 在子类中可以overvide关键字来重写父类
//   父类中使用final关键字可以防止重写
class superClass{
    var a = 10
    var b : Int{
        return a
    }
    final var c = 1
    func show(){
        print("superclass")
    }
}
class subClass:superClass{
    override func show(){
        print("subClass")
    }
    override var b:Int{//重写属性
        return super.a + 1
    }
    override var a :Int{//重写属性观察器
        didSet{
            print(a*2)
        }
        
    }
}
//31 swift的构造函数init方法 与oc不同 swift的init没有返回值
struct color{
    let red,green,blue:Double
    var len :              Double?//如果这个属性允许为空则要定义成optional type
    init(red:Double,green:Double,blue:Double){//如果在定义构造器时没有提供参数的外部名字,swift为每个构造器的参数自动生成一个和内部名字相同的外部名
        self.red = red
        self.green = green
        self.blue = blue
    }
    init(white:Double){
        red = white
        green = white
        blue = white
    }
    init(_red : Double,_green:Double,_blue:Double){//没有外部参数名字可用_表示
        self.red = _red
        self.green = _green
        self.blue = _blue
    }
}
//var r = color(10.0,20.0,30.0)没有外部参数的init函数调用
//值类型的构造器代理(即两个构造器的相互套用)
struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)//构造器之间的相互套用
    }
}
//父类和子类之间的构造器 正常情况下父类的init不会被子类继承 当然子类使用overvide方法是可以的
//可失败构造器,构造器可能会因为传入无效的参数值。缺少某种所需的外部资源。没有满足特定条件。而失败 一般用init!l来表示一个可失败的构造器
struct studRecord{
    let stname :String
    init!(stname:String){//这就是一个可失败的构造器
        if stname.isEmpty{
            return nil
        }
        self.stname = stname
    }
}
//32swift的析构 swift的析构函数用deinit来表示
//析构过程:1 swift会自动释放不再需要的实例来释放资源 2通过ARC来处理实例的内存管理 3使用自己的资源时需要进行一些额外的清理(当使用一个类来打开文件并且写入数据时需要在实例释放前关闭该文件)
var k = 0
class BaseClass{
    init(){
        k += 1
    }
    deinit{ //析构函数没有参数没有返回值
        k -= 1
    }
}
//33 ARC自动引用计数
//循环引用的例子
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) 被析构") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { print("Apartment #\(number) 被析构") }
}

// 两个变量都被初始化为nil
var runoob: Person?
var number73: Apartment?

// 赋值
runoob = Person(name: "Runoob")
number73 = Apartment(number: 73)

// 感叹号是用来展开和访问可选变量 runoob 和 number73 中的实例
// 循环强引用被创建
runoob!.apartment = number73
number73!.tenant = runoob

// 赋值nil断开 runoob 和 number73 变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁
runoob = nil
number73 = nil// 注意,当你把这两个变量设为nil时,没有任何一个析构函数被调用。
// 强引用循环阻止了Person和Apartment类实例的销毁,并在你的应用程序中造成了内存泄漏
//闭包形成的循环强引用
class HTMLElement {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)"
        } else {
            return "<\(self.name) />"
        }
    }
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
    
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
//实例的asHTML属性持有闭包的强引用。但是,闭包在其闭包体内使用了self(引用了self.name和self.text),因此闭包捕获了self,这意味着闭包又反过来持有了HTMLElement实例的强引用。这样两个对象就产生了循环强引用。
//解决循环引用的方式可以用弱引用和无主引用来解决
//当捕获引用有时可能会是nil时,将闭包内的捕获定义为弱引用。
//如果捕获的引用绝对不会置为nil,应该用无主引用,而不是弱引用。
//无主引用
class HTMLElement2 {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in //无主引用
        if let text = self.text {
            return "<\(self.name)>\(text)"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) 被析构")
    }
    
}

//创建并打印HTMLElement实例
var paragraph2: HTMLElement2? = HTMLElement2(name: "p", text: "hello, world")
print(paragraph!.asHTML())

// HTMLElement实例将会被销毁,并能看到它的析构函数打印出的消息
paragraph2 = nil

//弱引用
class Module {
    let name: String
    init(name: String) { self.name = name }
    var sub: SubModule?
    deinit { print("\(name) 主模块") }
}

class SubModule {
    let number: Int
    
    init(number: Int) { self.number = number }
    
    weak var topic: Module? //弱引用
    
    deinit { print("子模块 topic 数为 \(number)") }
}

var toc: Module?
var list: SubModule?

toc = Module(name: "ARC")
list = SubModule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

//34 swift中的is 和 as关键字
//is用来检查一个实例是否属于特定子类型
class Subjects {
}

class Chemistry: Subjects {
}

class Maths: Subjects {
}

let sa = [Chemistry(),Maths()]
for item in sa {
    if item is Chemistry {
    } else if item is Maths {
    }//is关键字的使用
}
//as向下转型用as  as!表示向下转型一定可以成功 as?表示向下转型不一定会成功
//35 any和anyobject的类型转换
//any表示任何类型
var exampleany = [Any]()
exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Any 实例")
//anyobject表示任何class类型的实例
let saprint: [AnyObject] = [Chemistry(),Maths()]
//35 swift扩展 使用关键字extension
extension Int {
   var add: Int {return self + 100 }
   var sub: Int { return self - 10 }
   var mul: Int { return self * 10 }
   var div: Int { return self / 5 }
}//向Int类型添加了5个属性并扩展其功能
//36swift协议
//协议规定了用来实现某一特定功能所必需的方法和属性。任意能够满足协议要求的类型被称为遵循这个协议
//37swift泛型
protocol FirstProtocol {
    // 协议内容
}
protocol AnotherProtocol {
    // 协议内容
}
protocol SomeProtocol {
    // 协议内容
}
//要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。
//遵循多个协议时,各协议之间用逗号,分隔。
struct SomeStructure: FirstProtocol, AnotherProtocol {
    // 结构体内容
}
//协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。
//协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 协议定义
}
//可以使用is和as操作符来检查是否遵循某一协议或强制转化为某一类型。

//38访问控制
//Swift为代码中的实体提供了四种不同的访问级别:public、internal、fileprivate、private。
//public 可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。
//internal  可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。
//fileprivate 文件内私有,只能在当前源文件中使用。
//private 只能在类中访问,离开了这个类或者结构体的作用域外面就无法访问。
//pulic是最高优先级 private是最低优先级
//子类的访问级别不得高于父类的访问级别
//常量、变量、属性不能拥有比它们的类型更高的访问级别,下标也不能拥有比索引类型或返回类型更高的访问级别
//常量、变量、属性、下标索引的Getters和Setters的访问级别继承自它们所属成员的访问级别
//协议的访问权限也是可以控制的

struct SHPoint{
    func test1(){}
    func test2(){}
    func test3(){}
}
var p = SHPoint()
p.test1()
p.test2()
p.test3()