iOS开发_swift 5.1入门基础语法

1. 基本数据类型

  • 1.1 常量和变量

    // 常量
    let a = 10
    
    // 变量
    var b = 11.1
    
  • 1.2 类型安全和类型推断

    • let 和 var 定义常量,编译器可以根据具体的值,来推断类型。
    • swift 是强类型语言,编译的时候如果赋值类型和声明类型不一致会报错。
  • 1.3 基本类型

    // 基本类型
    let aInt: Int = 10
    let aFloat: Float = 10.1
    let aDouble: Double = 10.0
    let aBool: Bool = true
    let aString: String = "a"
    let aWrapString:String = """
    百日依山尽,
    黄河入海流。
    """
    let aChar: Character = "a"
    
    • swift 中一切皆对象,所以基本类型也是类类型,也需要构造器转换。
      // 类型转换: 一切皆对象,利用构造器转换
      let aLong: Int64 = Int64(aFloat)
      
  • 1.4 类型别名

    // 类型别名
    typealias MyInt = Int
    let myInt: MyInt = 10
    
  • 1.5 元组

    • 元组是swift中新类型,python中也有这个类型。
    // 元组
    let tuple = (1,"json","errMsg")
    tuple.0
    tuple.1
    tuple.2
    
  • 1.6 可选类型

    • 可选类型:可能有值,可能没有值。
    • 其他类型:必须是有值的。
    • 可选类型:没有初始化,默认值是nil。
    • 其他类型:在使用前必须初始化。
    • 1.6.1 普通可选类型和隐式解析可选类型
      // 普通可选:类型?
      let aString: String? = "普通可选类型"
      // 普通可选获取值,必须强制解析
      let aStr = aString!
      type(of: aStr)  // -> String
      
      // 隐式解析可选类型: 类型!
      let bString: String! = "隐式解析可选类型"
      // 隐式解析可选类型,在定义时就制定了非空值,所以可以直接取值。
      let bStr = bString
      type(of: bStr) // -> String
      
    • 1.6.2 可选绑定
      let someOptional: String? = "hell world"
      
      if let constantName = someOptional {
          // String
          print(type(of: constantName)) 
          print(constantName)
      } else {
          // 绑定失败
      }
      type(of: bStr) // -> String
      
    • 1.6.3 可选链
      • 在java OC等语言中,没有可选类型,也没有可选调用链。所以会有 if else 的各种嵌套。
      if (person != null) {
          if (person.name != null) {
            print(person.name.length())
          }
      }
      
      • 在swift中语言中,可选调用链,整个链条上的值都可能是可选类型,如果值是nil,则终止后面的调用直接返回nil。
      class Person {
          var mac: Mac?
          init?(mac: Mac?) {
              guard let mac = mac else { return nil }
              self.mac = mac
          }
          
          // swift中的下标语法,使得获取某些值更加便捷。
          subscript(index: String) -> Int {
              switch index {
                  case "count": return self.mac?.name.count ?? 0
                  default:
                      return 0
              }
          }
      }
      
      class Mac {
          let name: String = "mac book pro"
      }
      
      let person = Person(mac: nil)
      
      print(person?.mac?.name.count ?? 0)
      print(person?["count"] ?? 0)
      
  • 1.7 运算符

    • 算术运算符:+ - * / %
    • 比较运算符:== != > < >= <=
    • 三元运算符:问题 ?答案1 : 答案2
    • 逻辑运算符: ! && ||
    • 区间运算符:
    // a..<b(半开区间)   
    for i in 0..<5 {
        
    }
    
    // a...b(闭区间)
    for i in 0...5{
      
    }
    
    // 单侧区间
    let names = ["a","b","c"]
    for name in names[...2] {
      print(name)
    }
    
    for name in names[1...] {
      print(name)
    }
    
    • 空合运算符:
      • a ?? b // a != nil ? a! : b
  • 1.8 断言

    • 断言主要用于测试程序。
    • assert(布尔表达式,“断言失败的信息”)
    let age = 3
    assert(age < 0,"age > 0")
    
    • 断言和异常的区别:
      • 断言用在哪些你知道绝对不会发生的事情上,来捕捉程序员自己的错误。
      • 异常捕捉用户或者环境的错误。
  • 1.9 宏定义

    • swift中没有宏定义,OC中的宏定义会转为swift中全局常量 。

2. 字符串

  • 字符串是结构体类型。
  • 在swift中结构体和枚举类型都是值类型的。值类型的数据在传参的时候是进行拷贝的。保证了数据安全性。
// 定义字符串
let aString = "hello"
let bString = """
    百日依山尽,
    黄河入海流。
"""

// 字符串拼接
var mutableString = "hello"
mutableString += "world"
mutableString.append(" han meimei")

// 字符串插值 \(表达式或者变量)
print("hello world \(type(of: mutableString))")
print("hello world \(mutableString + String(1))")

// 字符串长度
mutableString.count

// 大小写转化
mutableString.lowercased()
mutableString.uppercased()

// 前缀后缀
mutableString.hasPrefix("hello")
mutableString.hasSuffix("world")

// 是否相等
aString == bString

3. 集合类型

  • 集合是泛型。

  • 可变集合:将集合赋值给 var 型变量。

  • 不可变集合:将集合赋值给 let 型变量。

  • 注意:swift中的不可变集合和Java中不可变集合不一样的。swift不可变集合是真的不可变。 Java中的不可变集合是引用地址不能变,但是集合可以添加删除元素。

  • 3.1 Array

    // 简单语法
    var someInts = [Int]()
    
    // 泛型数组语法
    someInts = Array<Int>()
    someInts.append(3)
    
    // 空数组
    someInts = []
    
    // 重复数组
    var threeDoubles = Array(repeating:0.0, count:3)
    
    // 数组连接
    var anotherThreeDoubles = Array(repeating:2.4, count:3)
    var sixDoubles = threeDoubles + anotherThreeDoubles
    
    // 字面常量
    var shopping = [1, 3, 4, 5]
    
    // 是否为空
    shopping.isEmpty
    
    shopping[1]
    
    shopping.insert(3, at:0)
    
    shopping.removeLast()
    
    // 变量数组
    for item in shopping {
      print(item)
    }
    
    for (index, value) in shopping.enumerated() {
      print("item \(String(index + 1)) : \(value)")
    }
    
  • 3.2 Set

    • 一个类型存在Set中,该类型必须是可哈希化的。相等的对象 hashValue 必须相同。、
    a == b
    
    a.hashValue == b.hashValue
    
    • 所有的基本类型默认都是可哈希化的。因此可以作为Set的类型或者字典键的类型。
    • 可哈希化的类型,必须遵循Hashable 协议,实现 == 方法 和 hashValue值的放回。
    // 定义Set
    var letters = Set<String>()
    var set: Set<String> = []
    
    // 插入值
    letters.insert("a")
    
    // 清空元素
    letters = []
    
    // 字面量创建集合
    var favorite: Set<String> = ["hello", "world"]
    
    // 删除
    favorite.remove("hello")
    
    // 判断是否包含元素
    favorite.contains("hello")
    
    // 遍历集合
    var set: Set<String> = ["我","是","最","棒","的"]
    for item in set {
        if item == "是" {
            set.remove(item)
        }
    }
    
    • 注意:swift中的集合是可以遍历删除,Java中的集合如果遍历删除会出发fast-fail, 所以Java的变脸删除一般都是迭代器删除。
  • 3.3 Dictionary

    • swift 的字典使用 Dictionary<Key, Value> 定义,其中 Key 是一种可以在字典中被用作键的类型,Value 是字典中对应于这些键所存储值的数据类型。
    • 一个字典的 Key 类型必须遵循 Hashable 协议,就像 Set 的值类型。
    • 你也可以用 [Key: Value] 这样简化的形式去表示字典类型。虽然这两种形式功能上相同,但是后者是首选,
    // 定义一个字典
    var nameOfIntergers = [Int: String]()
    
    // 空字典
    nameOfIntergers = [:]
    
    // 字面量
    var nameOfInt = [1:"hello", 2:"world"]
    
    // 删除
    nameOfInt.removeValue(forKey:1)
    

4. 流程控制

  • 4.1 for-in

    var set: Set<String> = ["我", "是", "最", "棒", "的"]
    // 遍历Array和set
    for name in set {
        print(name)
    }
    
    // 遍历dictionary
    var dic = [1:"hello", 2:"world"]
    for (key, value) in dic {
        print("key = \(key), value = \(value)")
    }
    
    // 遍历区间
    for i in 0..<set.count {
        print(i)
    }
    
    print("\n \n")
    // 指定步长,遍历开区间
    for tickMark in stride(from: 0, to: 60, by: 5) {
        print(tickMark)
    }
    // j指定步长,遍历闭区间
    for tickMark in stride(from: 0, through: 60, by: 5) {
        print(tickMark)
    }
    
    
  • 4.2 while

    while 条件 {
       表达式
    }
    
    repeat {
      
    } while 条件
    
    • while 和 repeat while 的循环次数是一样的。
    • swift 没有 i++。 赋值表达式没有返回值。
  • 4.3 if

    if 条件 {
      // 表达式1
    } 
    else if 条件1 {
      
    } 
    else {
      
    }
    
  • 4.4 guard

    • 与if语句相同的是,guard也是基于一个表达式的布尔值去判断一段代码是否该被执行。
    • 与if语句不同的是,guard只有在条件不满足的时候才会执行这段代码。
    class Person {
        var mac: Mac?
        init?(mac: Mac?) {
            // mac == nil 时直接返回nil
            guard let mac = mac else { return nil }
            // mac != nil 才走下面的逻辑
            self.mac = mac
        }
    }
    
  • 4.4 switch

    • swift中的switch 更强大,进行模式匹配。
    • 字符串匹配
    let a = "a"
    
    switch "b" {
        case "a":
            print("a")
        case "b":
            print("b")
        default:
            print("默认值")
    }
    

    区间匹配

    let cout = 32
    switch cout {
    case 1...3:
        print("in 1...3")
    case 30...40:
        print("in 30...40")
    default:
        print("默认匹配")
    }
    

    元组

    let somePoint = (1,20)
    switch somePoint {
    case (0, 0):
        print("(0,0)")
    case (1, _):
        print("first = 1,second 随意")
    case (_, 20):
        print("first 随意,second = 20")
    default:
        print("没有匹配上")
    }
    

    值绑定

    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
        print("x = \(x), y = 0")
    case (2, let y):
        print("x = 2, y = \(y)")
    case (let x, let y):
        print("x = \(x),y = \(y)")
    }
    

    where 附加条件

    let yetAnotherPoint = (1,-1)
    switch yetAnotherPoint {
    case let (x,y) where x == y:
        print("x = \(x),y = \(y)")
    case let (x, y) where x == -y:
        print("x = \(x),y = \(y)")
    default:
        print("x = \(yetAnotherPoint.0),y = \(yetAnotherPoint.1)")
    }
    

    符合型

    let char = "a"
    switch char {
    case "a", "e", "i", "o", "u":
        print(char)
    default:
        print("其他char")
    }
    

    穿透

    var index = 10
    switch index {
    case 10:
        index += 1
        fallthrough
    default:
        index += 1
    }
    // 12 穿透执行
    print(index)
    
  • 4.5 控制转移

    ·continue break
    

5. 函数

  • 5.1 函数的定义

    • func 函数名(参数名:类型,参数名:类型)-> 返回类型 {
      // 执行体
      }
    func minMax(array: [Int]) -> (min:Int, max:Int){
        var currentMin = array[0]
        var currentMax = array[0]
        for value in array {
            if value > currentMax {
                currentMax = value
            } 
            else if value < currentMin{
                currentMin = value
            }
        }
        return (currentMin,currentMax)
    }
    
    let array = [1,3,4,5,6,7,8]
    print("min = \(minMax(array: array).min) max = \(minMax(array:array).max)")
    
  • 5.2 隐式返回函数

  • 如果函数体是一个单行return 语句,那么这个return可以省略掉。

func greeting(person: String) -> String {
  "hello," + person + "!"
}
  • 5.3 参数标签和参数名称

    • 参数标签使代码有更强的可读性。
    • 在参数名称前面指定参数标签。
    • 如果没有指定参数标签,参数名称也就是参数标签。
    • 下划线 _ 放到参数名称前面,可以省略掉参数标签,一般不这么用。
    func someFuncation(argumentLabel parameterName: Int) -> Int {
      // parameterName 参数名称, argumentLabel 标签参数
    }
    
    // from 是参数标签,hometown是参数名称
    func greet(person:String,from hometown: String){
        print(person+" from "+hometown)
    }
    
    greet(person: "wangbo", from: "haidian")
    
  • 5.4 默认参数值

    • 指定默认参数值,也是实现函数重载的方式。
    func someFuncation(param: Int, param1: Int = 2){
      
    }
    
    // 调用
    someFuncation(param: 3)
    someFuncation(param: 3, param1: 3)
    
  • 5.5 可变参数

    func arithmeticMean(_ numbers: Double...) -> Double {
        var total: Double = 0
        for number in numbers {
            total += number
        }
        return total / Double(numbers.count)
    }
    arithmeticMean(1, 2, 3, 4, 5)
    
  • 5.6 输入输出参数

    • 函数的参数默认是常量,不能修改的。如果想要修改参数的值,就要把参数定义为输入输出参数(参数类型前 inout) 。并且传入的参数是个变量。
    var ar = [Int]()
    
    // 参数类型前加 inout 表示是输入输出参数,可以修改
    func add(array:  inout [Int]) -> [Int] {
        for i in 1...5 {
            array.append(i)
        }
        return array
    }
    
    // 调用的时候实参前面加 &,表示这个参数可以被修改
    for item in add(array: &ar) {
        print(item)
    }
    
  • 5.7 函数类型

    func funcation(param: Int, param1: String) -> [Int]{
      
    }
    
    // 函数的类型
    (Int,String) -> [Int]
    
    • swift 中函数式一等公民,函数类型像其他类型一样可以定义变量, 也可以作为函数返回类型。
    typealias FuncationType = (Int,Int) -> Int
    
    func some(funcation: FuncationType) -> Int {
        let a = 10, b = 100
        return funcation(a,b)
    }
    
    let sum = some { (a, b) -> Int in
        return a + b
    }
    
  • 5.8 嵌套函数

    • 函数内定义函数。
    func chooseStepFunction(backward: Bool) -> (Int) -> Int {
        func stepForward(input: Int) -> Int { return input + 1 }
        func stepBackward(input: Int) -> Int { return input - 1 }
        return backward ? stepBackward : stepForward
    }
    

6. 闭包

  • swift的闭包和OC中block,Java中Lambda一样都是用于模块之间通讯的。

  • 闭包可以捕获上下文中的变量。

  • 闭包就是一个匿名的函数体。

  • Java 中的lambda就是一个匿名内部类。

  • 6.1 闭包表达式语法

    {(parameters) -> returnType in
        执行体
    }
    
    • 例子
      var names = ["a","dsf","weea","3psd"]
      
      names.sort(by: { (s1: String, s2: String) -> Bool in
          return s1 > s2
      })
      
      for item in names {
          print(item)
      }
      
    • swift 的表达式拥有更简洁的风格。
    • 利用上下文推断参数和返回值类型
    • 隐式返回单表达式闭包,单表达式闭包可以省略return关键字。
    • 参数名称缩写。
    • 尾随闭包语法。
    • 根据上下文推断类型
    • 因为闭包是作为函数的参数传入的,可以根据参数的类型来推断闭包的类型,所以闭包的 参数类型 和 返回类型 都可以省略。
      names.sort(by: { s1, s2 in return s1 < s2 })
      
    • 单表达式隐式返回
      names.sort(by: { s1,s2 in s1 > s2 })
      
    • 参数名缩写
      names.sort(by:{ $0 > $1})
      
    • 运算符方法
      names.sort(by: > )
      
  • 6.2 尾随闭包

    • 如果将闭包表达式作为最后一个参数传递给函数,将这个闭包替换成尾随闭包的形式。
    • 尾随闭包不用写参数标签。
    func someFunctionThatTakesAClosure(closure: () -> Void) {
        // 函数体部分
    }
    
    // 以下是不使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure(closure: {
        // 闭包主体部分
    })
    
    // 以下是使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure() {
        // 闭包主体部分
    }
    
  • 6.3 值捕获

    • 闭包可以捕获上下文中的常量或变量。
    • 闭包就是函数内部与函数外部连接的桥梁。
    • 闭包的用途:
      • 读取函数内部的变量。
      • 让这些变量的值始终在内存中。
    func f1(amount: Int) -> () -> Int{
        var total = 10
        func f2() -> Int{
            total += amount
            return total
        }
        return f2
    }
    
    let res = f1(amount: 5)
    print(res())  // 15
    print(res())  // 20
    
    let res1 = f2(amount: 5)
    print(res()) // 15
    
    • f1 是 f2的父函数,f2赋值给一个全局变量,f2一直在内存中,f2依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。
    • 闭包是引用类型,一个对象属性赋值给一个闭包,如果闭包直接访问了该对象或该对象的成员,就会引起循环引用。
  • 6.4 逃逸闭包

    • 闭包作为函数的参数,分为逃逸闭包和非逃逸闭包。默认是非逃逸闭包。逃逸闭包在闭包类型前面加上 @escaping 。
    • 逃逸闭包的比函数体要晚执行(比如异步回调执行闭包)。
    • 非逃逸闭包和函数提一起执行。
    // 逃逸闭包
    func sun(callBack: @escaping (String) -> Void){
        DispatchQueue
            .global()
            .asyncAfter(deadline: DispatchTime.init(uptimeNanoseconds: 1000)) {
            callBack("我逃出sun的生命周期")
        }
        print("sun 执行完毕")
    }
    
    sun { print($0) }
    
    // 非逃逸闭包
    func moon(callBack: (String) -> Void){
        print("moon 执行")
        callBack("我没有逃出moon的生命周期")
    }
    
    moon { print($0) }
    
  • 6.5 自动闭包

    var count = 10
    let f = { count += 10 }
    
    print(count)
    f()
    print(count)
    

7. 类

  • 7.1 属性

    • 7.1.1 存储属性
      • 可以是 let var
      • 要么默认初始化,要么init构造器初始化
      • 可选类型的存储属性,没有在构造器初始化,会有默认初始化 nil
      • 结构体和枚举赋值给常量,它的变量存储属性也不能修改。
      class Person {
          let id: Int
          var name: String = "wangbo"
          // var bb: String
          // 如果没有默认初始化,就必须在init中初始化
          
          // 延迟加载存储属性,第一次调用时才初始值,延迟属性必须是var
          lazy var array = Array(repeating: 0, count: 3)
          
          init(id: Int) {
              self.id = id
          }
      }
      // 存储属性也是可以直接修改和取值的
      let person = Person(id: 10)
      person.name = "hh"
      person.array = Array(repeating: 10, count: 3)
      print(person.name)
      
      • 全局变量和局部变量都是存储型变量。
      • 全局变量都是延迟计算的,跟延迟存储属性类似,但是不用 lazy 标志。
    • 7.1.2 计算属性
      • 计算属性提供一个 getter 和一个可选的 setter方法。来间接获取或设置属性值。
      • 计算属性其实就是 java 里的 getter 和 setter 方法
      class Person {
          var _age :Int = 0
          var age: Int {
              get {
                  return _age
              }
              set {
                  _age = newValue
              }
          }
      }
      
      let person = Person()
      person.age = 10
      print(person.age)
      
      • 只读计算属性
      class Person {
          // 只读计算属性,省略掉 get{ return 10 }
          var age : Int {
              return 10
          }
      }
      
      let person = Person()
      print(person.age)
      
    • 7.1.3 属性观察器
      • 属性观察器一般为存储属性提供的,计算属性可以,但是没必要,在setter方法中就可以监听变化。
      class Person {
          var name = "hh" {
              willSet {
                  print("name = \(self.name) 将变为 \(newValue)")
              }
              didSet {
                  print("旧的值是 \(oldValue) 当前值\(self.name)")
              }
          }
      } 
      
      let person = Person()
      person.name = "www"
      
    • 7.1.4 类型属性
      • static修饰的属性就是类型属性
      class Person {
          static let a: String = "hello"
      }
      
      Person.a
  • 7.2 方法

    • 7.2.1 普通方法
      • 结构体,枚举,类都可以有方法。
      • 特殊点:swift的类方法,可以用static修饰,也可以用class修饰。
      • 区别:
        • static 修饰的类型方法不能被复写。
        • class 修饰的类方法可以被子类复写。
      class Person {
          static let a: String = "hello"
          
          // 实例方法
          func work(at where: String) -> Void {
              print("at \(`where`)" world)
          }
          
          // 不可以被复写的类方法
          static func sayHello() {
              print("hello")
          }
          
          // 可以被子类复写的类方法
          class func sayWorld() {
              print("world")
          }
      }
      
      class Teacher: Person {
          override class func sayWorld() {
              print("teacher say world")
          }
      }
      
    • 7.2.2 构造器
      • 构造器没有返回值。
      • swift 的类,如果存储属性没有指定默认值,就必须要有构造器。
      class ShoppingListItem {
          var name: String?
          var quantity = 1
          var purchased = false
      }
      var item = ShoppingListItem()
      
    • 7.2.3 指定构造器和便利构造器
      • 一个类必须有一个指定构造器
      • 便利构造器必须依赖于指定构造器
      class Person {
          let a: Int
          var b: String
          // 指定构造器
          init(a: Int, b:String) {
              self.a = a
              self.b = b
          }
          
          // 便利构造器
          convenience init(a: Int) {
              self.init(a: a, b:"haha")
          }
      }
      
      let pe = Person(a: 10)
      let p2 = Person(a: 12,b:"world")
      
    • 7.2.4 可失败构造器
      • 可失败构造器一般用于结构体,表示model层数据可能失败。
      • 构造器通过返回一个 nil 表示这是个可失败构造器。
      struct Person {
          let name: String
          init?(name: String) {
              if name.isEmpty {
                  return nil
              }
              self.name = name
          }
      }
      
      let person = Person(name: "")
      // Optional<Person>
      print(type(of: person))
      
    • 7.2.5 必要构造器
    class SomeClass {
        required init() {
            // 表明子类必须实现该构造器
        }
    }
    
  • 7.3 析构器

    deinit(){
        // 释放资源
    }
    
  • 7.4 继承

    • swift的类如果不指定父类,是没有父类的。不像其他语言默认继承 Object类。
    • 子类可以继承父类的属性,方法,并重写父类的属性和方法。
    • 方法前加 final 修饰符,这个方法不能被重写。
    • 类前加 final 修饰符,这个类不能被继承。
  • 7.5 类型转换

    • 7.5.1 判断类型 is
    class Person {
        let name: String
        init(name: String) {
            self.name = name
        }
    }
    
    class Teacher: Person {
        var age: Int
        init(name: String,age: Int) {
            self.age = age
            super.init(name: name)
        }
    }
    
    let teacher = Teacher(name: "hh", age: 29)
    if teacher is Person {
        print("teacher 是Person的子类")
    }
    
    • 7.5.2 类型转换 as? as!
    let teacher = Teacher(name: "hh", age: 29)
    guard let tea = (teacher as? Person) else {
        print("转换失败")
    }
    print("转换成功")
    
    • as? 表示可能转换失败,返回nil。as! 表示一定能转换成功。
  • 7.6 扩展

    • 扩展可以在不访问一个类,结构体,枚举,源代码的基础上,给类,结构体,枚举添加一些属性,方法,实现协议等。替代之前的工具类。
    • 添加计算型实例属性和计算型类属性
    • 定义实例方法和类方法
    • 提供新的构造器
    • 定义下标
    • 定义和使用新的嵌套类型
    • 使已经存在的类型遵循(conform)一个协议
    extension SomeType {
      // 在这里给 SomeType 添加新的功能
    }
    
    • 在项目中,扩展经常用来格式化代码和实现工具类。
    • 7.6.1 扩展属性
    extension Double {
        var km: Double { return self * 1_000.0 }
        var m: Double { return self }
        var cm: Double { return self / 100.0 }
        var mm: Double { return self / 1_000.0 }
        var ft: Double { return self / 3.28084 }
    }
    
    • 7.5.2 扩展构造器
    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()
    }
    
    extension Rect {
        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)
        }
    }
    
    • 7.5.3 扩展方法
    extension Int {
       func repetitions(task: () -> Void) {
           for _ in 0..<self {
               task()
           }
       }
     
        mutating func square() {
           self = self * self
       }
    }
    
    • 7.5.4 扩展下标
    extension Int {
        subscript(digitIndex: Int) -> Int {
            var decimalBase = 1
            for _ in 0..<digitIndex {
                decimalBase *= 10
            }
            return (self / decimalBase) % 10
        }
    }
    
    • 7.5.5 嵌套类型
    extension Int {
        enum Kind {
            case negative, zero, positive
        }
        var kind: Kind {
            switch self {
            case 0:
                return .zero
            case let x where x > 0:
                return .positive
            default:
                return .negative
            }
        }
    }
    
  • 7.6 嵌套类

    • swift中的嵌套类型,跟Java中的静态内部类一样。
    class Person {
        var age: Int = 0
        
        class Kind{
            var name: String?
            init?(name: String?) {
                guard let name = name else { return nil }
                self.name = name
            }
        }
    }
    
    let kind = Person.Kind(name: nil)
    print(kind?.name ?? "")
    
  • 7.7 访问控制

    • open > public > interal > fileprivate > private
    • open: 包以外的类可以访问,也可以继承,override方法。
    • public:包以外的类可以访问,但是不能继承,override方法。
    • internal: 包访问级别。相当于package。默认可写可不写。
    • fileprivate: 访问级别所修饰的属性或者方法在当前的 Swift 源文件里可以访问。
    • private:只有同一个类中的方法属性才能访问。

8. 结构体

  • 类和结构的相同点:
    • 都有存储属性和计算属性
    • 都可以定义方法
    • 定义下表操作
    • 定义构造器
    • 通过扩展以增加默认实现之外的功能
    • 遵循协议
  • 类和结构的不同点:
    • 类是引用类型,结构体是值类型
    • 结构体不允许继承,就像final class一样,是个常量类。
    • 结构体可以不定义构造器,默认会有一个按照属性次序定义的构造器。
    • swift中除了class是引用类型,之外的都是值类型。
    • 值类型赋值给 let 常量之后,即使属性是可变属性也可以修改。
    • 引用类型赋值给 let 常量之后,可变属性还是可以修改的。
    • 值类型的比较 == != 相等。
    • 引用类型的比较 === !== 相同。
    struct PersonInfo{
        let name: String
        var age: Int
        
        func say(word: String) -> Void {
            print(word)
        }
        
        mutating func add() -> Int {
            age = age + 1
            return age
        }
    }
    
    let person = PersonInfo(name: "haha", age: 10)
    
  • 结构体的普通方法是不能修改属性的,只能在构造器中修改属性值。如果强行修改,只需在方法前加上 mutating 修饰符。
  • 结构体如果没有定义构造器,会有一个默认的逐一成员构造器。

9. 枚举

  • 9.1 枚举语法

    enum {
      case north
      case south
      case east
      case west
    }
    
  • 9.2 枚举成员的集合

    enum Beverage: CaseIterable {
      case coffee,tea,juice
    }
    
    for item in Beverage.allCases{
        print(item)
    }
    
  • 9.3 原始值

    • 枚举成员在定义时可以被默认值他填充。填充的值就是原始值,原始值的类型就是枚举继承的类型。
    enum Type: String{
        case ALL = "all"
        case NORMAL = "normal"
    }
    
  • 9.4 原始值隐式赋值

    // Int 是原始值类型,隐式原始值是递增的
    enum Planet: Int {
        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    }
    
    // String 是原始值类型,隐式原始值为成员名
    enum CompassPoint: String {
        case north, south, east, west
    }
    
    // rawValue属性可以访问枚举成员的原始值
    print(Planet.venus.rawValue)  // 输出2
    print(CompassPoint.north.rawValue)  // 输出north
    
    
    // 使用原始值初始化枚举值
    let planet = Planet(rawValue: 3)  // Planet.earth
    
  • 9.5 枚举值的关联值

    • 感觉用的不多
    // 枚举值的关联值
    enum BarCode {
        case upc(Int, Int, Int, Int)
        case qrCode(String)
    }
    
    let productCode = BarCode.upc(1, 23, 39, 219)
    let productCode1 = BarCode.upc(3, 8, 9, 78)
    
    switch productCode {
    case let .upc(x, y, z, q):
        print("x= \(x), y = \(y) ,z = \(z) ,q = \(q)")
    default:
        print("默认值")
    }
    

10. 协议

  • 10.1 属性

    • 协议里可以有属性,遵循这个协议的类结构体枚举都必须要有这个属性。
    • 必须是 var
    • 类型后面要有
    protocol SomeProtocol{
        var name: String {get set}
        static var here: String { get }
    }
    
    class Person: SomeProtocol{
        var name: String
        
        static var here: String = "person"
        
        init(name: String) {
            self.name = name
        }
    }
    
    let person = Person(name: "hh")
    print(person.name)
    person.name = "ww"
    print(Person.here)
    
  • 10.2 方法

    protocol SomeProtocol {
        // 值类型修改属性的方法必须是 mutating修饰
        mutating func changeName() -> String
    }
    
    class Person: SomeProtocol {
        func changeName() -> String {
            return "hehe"
        }
    }
    
    struct Man: SomeProtocol {
        var name: String
        mutating func changeName() -> String {
            name = "hhh"
            return name
        }
    }
    
  • 10.3 协议合成

    • 协议组合使用 SomeProtocol & AnotherProtocol 的形式。你可以列举任意数量的协议,用和符号(&)分开。
    protocol Named {
        var name: String { get }
    }
    protocol Aged {
        var age: Int { get }
    }
    struct Person: Named, Aged {
        var name: String
        var age: Int
    }
    func wishHappyBirthday(to celebrator: Named & Aged) {
        print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
    }
    let birthdayPerson = Person(name: "Malcolm", age: 21)
    wishHappyBirthday(to: birthdayPerson)
    
  • 10.4 协议扩展

    • 协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现。
    • 计算属性提供默认实现
    • 方法提供默认实现
    • extension Protocol where Self: 类 限定了协议Protocol的扩展实现,只能由类的对象调用
    protocol SomeProtocol {
        // 普通方法
        func add(age: Int) -> Int
        // 属性
        var age: Int{get set}
        // 构造器
        init(age: Int)
    }
    
    // 协议扩展
    extension SomeProtocol {
        // 实现计算属性
        var name: String {
            return "hhh"
        }
        
        // 实现方法
        func work(here: String) -> String {
            return "我在 \(here) 工作"
        }
    }
    
    // 协议扩展实现的限定,只能由Person对象调用
    extension SomeProtocol where self: Person {
        func sleep(time: String) {
            print("睡觉)
        }
    }
    
    class Person: SomeProtocol {
        func add(age: Int) -> Int {
            self.age = self.age + age
            return self.age
        }
        
        var age: Int
        
        required init(age: Int) {
            self.age = age
        }
    }
    
    let person = Person(age: 10)
    person.add(age: 10)
    person.work(here: "北京")
    

11. 泛型

  • 11.1 类结构体泛型

    struct Stack<T>{
        var items:[T] = [T]()
        
        var count: Int{
            return items.count
        }
        
        mutating func push(item: T) {
            items.append(item)
        }
        
        mutating func push(items: [T]){
            for item in items {
                self.items.append(item)
            }
        }
        
        mutating func pop() -> T? {
            return items.popLast() ?? nil
        }
    }
    
    var stack = Stack<Int>()
    stack.push(item: 1)
    stack.push(items:[2,3,4,5])
    stack.count
    
  • 11.2 typealias 支持泛型

    typealias StringDictionary<T> = Dictionary<String, T>
    typealias DictionaryOfStrings<T : Hashable> = Dictionary<T, String>
    typealias IntFunction<T> = (T) -> Int
    typealias Vec3<T> = (T, T, T)
    
  • 11.3 协议泛型

    protocol SomeProtocol {
        associatedtype T
    }
    

12. 异常处理

  • 在 Swift 中,错误用遵循 Error 协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。
  • 12.1 错误的定义

    • 错误实现Error协议的类。一般用枚举值表示。
    enum VendingMachineError: Error {
        case invalidSelection                     //选择无效
        case insufficientFunds(coinsNeeded: Int) //金额不足
        case outOfStock                             //缺货
    }
    
  • 12.2 错误处理

    • 12.2.1 do-catch
      do {
          try expression
          statements
      } catch pattern 1 {
          statements
      } catch pattern 2 where condition {
          statements
      } catch {
          statements
      }
      
      • catch 之后是模式匹配。
    • 12.2.2 try?
      func someThrowingFunction() throws -> Int {
          // ...
      }
      
      let y: Int?
      do {
          y = try someThrowingFunction()
      } catch {
          y = nil
      }
      
      // x 是个可选类型,效果和上面一样,try?是个简洁的语法
      let x = try? someThrowingFunction()
      
    • 12.2.3 try!
      • 禁止错误的传递。try!认为后面的表达式不会抛出错误。
      let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
      
    • 12.2.4 throw
      • 错误的传递
      func canThrowErrors() throws -> String
      
      func canThrowErrors() throws
      

13. 内存管理

  • swift 和 OC都是引用计数管理内存,当一个对象的引用计数 = 0 时,就会被立即回收内存。
  • JAVA语言是垃圾回收器,只有内存压力触发垃圾回收器回收时,才会清理内存。
  • 所以,swift的内存利用率更高。JAVA内存利用低容易触发OOM。
  • 13.1 弱引用

    • 弱引用是个可选类型,引用对象可以是个nil。不会持有的对象保存强引用。
    class Person {
        let name: String
        init(name: String) { self.name = name }
        var apartment: Apartment?
        deinit { print("\(name) is being deinitialized") }
    }
    
    class Apartment {
        let unit: String
        init(unit: String) { self.unit = unit }
        weak var tenant: Person?
        deinit { print("Apartment \(unit) is being deinitialized") }
    }
    
  • 13.2 无主引用

    • 无主引用不是可选类型,必须有一个值。也不会对持有的对象强引用。
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) is being deinitialized") }
    }
    
    class CreditCard {
        let number: UInt64
        unowned let customer: Customer
        init(number: UInt64, customer: Customer) {
            self.number = number
            self.customer = customer
        }
        deinit { print("Card #\(number) is being deinitialized") }
    }
    
  • 13.3 闭包引起的循环引用

    • 获列表中的每一项都由一对元素组成,一个元素是 weak 或 unowned 关键字,另一个元素是类实例的引用(例如 self)或初始化过的变量(如 delegate = self.delegate)
    lazy var someClosure = {
        // 捕获列表
        [unowned self, weak delegate = self.delegate] 
        (success, errorCode, errorMsg)
        in
        // 这里是闭包的函数体
    }
    
posted @ 2018-11-12 23:01  CH520  阅读(258)  评论(0编辑  收藏  举报