Swift 3.0 学习笔记

  • 苹果宣称Swift的特点是: 快速,现代,安全,互动 , 而且明显优于OC
  • 界面可以使用CocoaCocoa Touch框架
  • Swift中取消了预编译指令包括宏
  • Swift取消了Objective-C的指针及其他不安全访问的使用
  • 舍弃OC早期应用的Smalltalk的语法"[]",全面改为句点表示法
  • 提供了类似Java的命名空间(namespace), 泛型(gegeric), 运算对象重载(operator overloading)
  • 在Swift中, 可以省略分号;, 使用换行代替,也可以添加. 但是有一种情况必须加分号:同一行代码上有多条语句时.
  • 3.0对Foundation框架做了重大调整:
  • 去除了NS前缀
  • 将绝大部分class转换为struct
  • 参考网站:
  • https://swift.org
  • https://developer.apple.com/swift/blog/

命名

  • 标识符可以使用中文名称或表情, 因为Swift采用Unicode编码.
  • 注意点:
    不能包含数学符号, 箭头, 非法无效的Unicode字符(⚽️), 关键字;
    不能以数字开头, 不能是单独一个下划线_; .......
  • 采用"驼峰式"的命名规则.

注释

  • 相比OC,多行注释可以嵌套多行注释.
/* 外层注释
/* 内层注释
     内层注释 */
外层注释 */

变量与常量

  • 常量使用let关键字, 变量使用var关键字.
  • Swift严格要求变量在使用之前必须进行初始化
var str = "Hello, playground"
let girl = " 少女"
//girl = "元气少女" // 报错, 常量重定义
var num = 1
//num = "哈哈" // 报错, num已经指定为Int类型, 无法重新设置为String类型.
var good:Int = 2 // 显示指定为Int类型, 编译提供联想类型功能.

var myTableView = UITableView()
public let titleArray = ["基本", "嵌套", "动画"]

类型推测

  • 一般来说,没有必要明确指定变量\常量的类型.
  • Swift自动推测所声明变量或常量的类型, 是强类型语言
  • 不可以中途更换类型, 会在编译期检查类型, 也可以显示的指明变量的类型.(ps.赋值后再编译)
  • typealias关键字定义类型的别名,相当于C语言的typedef
 var age: Int = 2; // 显示指定为Int类型, 编译提供联想类型功能.

输出常量与变量

  • 使用print( )在控制台输出数据, 使用\( )输出变量.
print(", 恭喜恭喜") // 在控制台输出数据
var name = "Sara"
print("Who is the girl? \(name)")

字符串的简单操作

  • 用加号+做字符串的拼接
let str1 = "Hello, playground"
let str2 = "123"
var str = str1 + str2
  • 用反斜线 \ 和小括号 ( ) 做字符串插值 (把常量\变量插入到字符串当中)
var age  = 10
var hand = 2
// 两种方式转为字符串
var dest = String(age)
var stt = "\(hand)"
  • 返回指定编码的对应的字节数量
// UTF8的编码(0~4个) 每个汉字是3个字节
print(st.lengthOfBytes(using: .utf8))
  • 用characters.count计算字符串的长度
var str = "Hello, playground"
print(str.characters.count)  // 17\n
  • 字符串比较
let str = "Hello, playground"
let str1 = "hello"
if str == str1 {
    print("字符串相等")
}
if str.isEmpty {
    print("字符串为空")
}

基本数据类型

  • 类型: 整型(Int), 浮点型(Float,Double), Bool型, 元组(Tuple), 可选型(Optional), Array, Dictionary, Character
  • 在Swift中数据类型的首字母都是大写.
  • 如果数值超出了取值范围,编译器直接报错

数字格式

  • 数字可以增加额外的格式,使得容易阅读
// 可以增加额外的零 
let money = 001234 // 1234
// 可以增加额外的下划线_
let  money = 1_000_000 // 1000000

运算符

  • 范围运算符: ..< , ...
 a..
  • 遍历范围
// 按顺序从范围中取值赋值给index,每取一次值,就执行一次循环体
for index in 1...5{
}
// 遍历字符串
for character in "abcde".characters{
    print(character)
}
  • 忽略循环变量
// 如果不需要用到范围内的值,可以使用下划线_进行忽略
for _ in 1...5{}
}
  • 溢出运算符: &+ , &-, &* , &/ ,&%
var x = UInt8.max; // 255
var y = x &+ 1; // 0
注意: 
1.swift赋值运算符没有返回值,好处是防止误用=和==
    if (x = y){} // 错误,因为x=y 没有返回具体的值, 相比C语言非0即为真
 2.swiftd %支持浮点数的计算
    8%2.5 // 0.5      

整型

  • 在Swift中, 提供Int与UInt两种类型, 后面携带数字表示整数位数, 如Int8, 默认使用Int即可, 在64位是Int64, 32位是Int32.
  • 提供max和min属性来获取某个类型的最大值和最小值.
  • 在定义变量时不用在意有无符号,数据长度的问题; 尽量使用Int,在意可以考虑代码的简洁和可复用性.
var max = Int.max
var min = Int.min
var maxu = UInt.max
var minu = UInt.min
  • 整数的四种表现形式
 1. 十进制数:没有前缀
    let i1 = 10  //10
2. 二进制数:以0b为前缀
    let i2 = 0b1010  //10
3. 八进制数:以0o为前缀
    let i3 = 0o12  //10
4. 十六进制数:以0x为前缀
    let i4 = 0xA  //10

浮点型

  • 常见的Float是32位浮点数, Double是64位浮点数.
  • 精确度: Float:至少6位小数; Double:至少15位小数
  • 如果没有明确说明类型,浮点数默认就是Double类型
let score: Float = 99.89
let score = 99.89f  //错误,swift没有此写法
  • 浮点数可以用十进制和十六进制2种表现形式
 1.十进制(没有前缀)
   没有指数: let d1 = 12.5
   有指数:     let d2 = 0.123e5
 2.十六进制(一定要有指数)
  let d3 = 0xC.8p0 // 12.5     p=2的N次方

Bool型

  • 两个常量, true或者false, 不再接收数字类型转型.
var isGood = true
if (isGood) {  //== if(true)
   print("好的!")
}
//isGood = 0; // 错误,不接受数字类型转型

元组Tuple

  • 元组把多个不同类型组成一个类型, 使用括号( )定义, 使用逗号,分隔. 使用元组定义确定形式的信息.
 var student = ("张三", 18, "山西") // 定义类型
 let name = student.0;
 let age = student.1;
 let home = student.2; 
  • 也可以给各个成员变量命名, 使用key:value的形式.
 var student = (name:"张三", age:18, home:"山西")
 let sname = student.name;
 let sage = student.age;
 let shome = student.home;
  • 元组之间可以相互转换, 使用下划线_表示省略的属性.
 var (showName, showAge, _) = student
 print("我叫\(showName), 今年\(showAge)岁")

可选项Optional

定义使用  `?`        解包使用 `!` ,准备计算

变量可选项的默认值是 nil
常量可选项没有默认值,主要用于在构造函数中给常量设置初始数值
  • 如下情况可以使用可选类型
    • 它有值但不确定
    • 它没有任何值 nil,不是任何数据类型,不能参与运算
  • 在定义的常规类型后面添加?, 即表示可选型, 如age:Int?, 如果有值, 则返回常规类型, 否则, 返回nil(空值).
 var ss: Int? = nil  // 空值
 var myAge:Int?
 myAge = Int("Spike")   //ps. 在Swift2.0中, 遗弃toInt( )方法, 使用Int( )转换.
  • 在Swift中, 所有类都会被初始化, 即使没有赋值的可选型, 会默认初值nil.
  • 在处理可选型时, 要注意解包, 即获取内部的值, 未解包时, 会显示Optional( ).
myAge = Int("15")
print("我今年\(myAge)岁") //输出:我今年Optional(15)岁
  • 解包操作, 在确定变量含有正确值时, 使用叹号!进行解包, 对空值(nil)解包时, 会造成崩溃
    一定需要注意!
    正常解包前需要判空.
    *
 myAge = Int("")
 if (myAge != nil) {
    print("我今年\(myAge!)岁")
 }
Swift 3.0 学习笔记_第1张图片
可选项.png

流程控制

1.条件不需要()
2.语句必须有{}
3.()表示空执行

#### switch
1.可以对任意类型的值进行分支,不再局限在整数!
2.不需要 break,执行完case对应的代码后默认会自动退出switch语句; 
3.所有分支至少需要一条指令语句
4.如果 case 多值,使用`,`

- case的多条件匹配
        let score = 90
        switch score/10 {
        case 10,9:
            print("优秀")
        default:
            break
        }

- case的范围匹配
        switch score {
        case 90...100:
            print("优秀")
        default:
            break
        }

- case匹配元组
        let student = ("小明", 18)
        switch student {
        case ("小红", 18):
            print("是小红")
        case (_, 18):
            print("是18岁")
        case (_, 16...19):
            print("aaa")
        default:
            break
        }

- fallthrough
    执行完当前case后,会接着执行fallthrough后面的case或者default语句; 但是fallthrough后面的case条件不能定义常量和变量

#### 标签
可以用于明确指定退出那个循环
biaoqian: 
   循环

OC与Swift语法比较

/**
// 1.@UIApplicationMain 程序的入口 (没有main函数)
// 2.只有.swift 没有.h/.m  在Swift中默认全局共享
// 3.所有的代码,都包装在{}(函数) 默认方法都有一个缩进!

 1. OC     [[UIView alloc] initWithXXX:]
    Swift  UIView(XXX:)
           UIView()
 
    类名() == alloc / init 等价
 
 2. 类方法
    OC      [UIColor redColor]
    Swift   UIColor.red
            2.0 UIColor.redColor()

 3. 访问当前对象的属性,可以不使用`self`
    建议: 都不用,在编译器提示的时候再添加,会对`语境`有更好的体会
    原因: 闭包(类似于OC-block),需要使用 self
 
 4. 没有分号`;`
    `;`目的是分隔语句,在Swift中默认不需要, 除非一行有多条语句,需要`;`间隔
 
 5. 枚举类型
    OC    UIButtonTypeContactAdd
    Swift `.`contactAdd
          
    let btn = UIButton(type: .contactAdd)

 6. 监听方法
    OC    @selector
    Swift #selector   如果带参数,不需要使用`:`
    2.0   直接使用`""`,需要使用`:`
    
    btn.addTarget(self, action: #selector(clickme), for: .touchUpInside)
    func clickme(btn: UIButton) -> () {
        print(#function)
        print("测试按钮")
        print(btn)
    }

 7. 调试
    OC      NSLog
    Swift   print 
            - 没有时间
            - 效率高于NSLog
 
    OC      __FUNCTION__
    Swift   #function

8. 注释
    从 Xcode8.0 开始,目前所有的插件都无法工作
    `///`   option + cmd + /    增加文档注释
    `vi.backgroundColor = #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1)`  
     ->color + 回车  添加颜色块
 
    // MARK:  视图生命周期
    // TODO:  还需要做的事情
    // FIXME: 需要完善修改的地方
 
 9. 自动推导 变量\常量的类型会根据右侧的代码执行结果,推导对应的类型 `option + click`
    强类型   不可以中途更换类型, 会在编译期检查类型, 也可以显示的指明变量的类型.(ps.赋值后再编译)
    不存在基本数据类型 都是结构体

    // 类型转换 as
       Swift 中除 String 外,绝大多数使用as 需要?/!
       as?/as! 直接根据前面的返回值来决定
       注意: if let / guard let 判空语句,一律使用 as?
 
 10. ?? 
    是一个简单的三目 , 解决可选项解包时的代码"尴尬"
    对于Swift项目中对Optional Value的安全有效处理;
 
    - 如果有值,使用值
    - 如果没有值,使用??后面的值替代

     let str: String? = "hello"
     print((str ?? "") + "world!") //helloworld!
     print(str ?? "" + "world!")   //hello
     // 可见: ??操作符的优先级较`低`,在使用的时候最好用()括起来

 11. if let/var 连用语法,目的是判断值(在赋值的时候判断值,不是单纯的 if,不需要解包)->作用域{}
     guard let 和 if let 刚好相反,降低分支层次 ,守护一定有值,如果没有直接返回 ->作用域不止{}
 
    // 使用同名的变量接收值,在后续使用的都是非空值,不需要解包
    guard let name = name else {}
    if let name = name {}

 12. 传统 for 已被取消(3.0后)
     ++i i++ 已被取消(3.0后), 直接使用 i += 1
    
    // 反序遍历
    for i in (0...9).reversed() {
        print(i)
    }

 13. 字符串
   String 是一个结构体,性能更高;   NSString 是一个 OC 对象,性能略差
    - 目前具有了绝大多数 NSString 的功能
    - 支持直接遍历!       `for c in  "hello".characters {  }`
    - as 类似于 OC 类型转换(NSString *)
      // 使用`值 as 类型`类型转换
      let ocStr = st as NSString
      print(ocStr.length)
    
    - 字符串截取
      var st = "hello"
      st = st.substring(from: "he".endIndex)
 
      st = st.substring(with: st.range(of: "ll")!)
      // 或
      guard let range = st.range(of: "ll") else {
          print("没有找到字符串")
          return
      }
      print(st.substring(with: range))

 14. 数组
    func arrayDemo() {     

        // 初始化
        var array = [String]()   

        let arr = ["aaa", "bbb", "ccc"] //[String]        
        let arr2 = [1,2,3,4,5] // [Int] 
        let p = CGPoint(x: 10, y: 100)// CG结构体
        let arr3 = [p] //[CGPoint]
        
        // 混合数组: 开发中几乎不用,因为数组是靠下标索引
        // 如果数组中数据类型不一致,自定推导的结果`[NSObject]`
        // 还有一种类型`[AnyObject]`-> 任意对象(Swift 中一个类可以没有任何`父类`)
        // 在混合数组中, CG结构体需要包装 `NSValue()`,整个数组还要加`as [Any]`
        let arr4 = ["张", 1, NSValue(cgPoint: p)] as [Any]  //[Any]
        
        // 按照下标遍历
        for i in 0..元组
        for e in arr.enumerated() {
            print("\(e.offset) \(e.element)")
        }
        for (n, s) in arr.enumerated() {
            print("下标:\(n) 元素:\(s)")
        }
        // 反序遍历
        for (n, s) in arr.enumerated().reversed() {
            print("下标:\(n) 元素:\(s)")
        }

        // 数组 增/删/改
        array.append("bread")  // apend函数追加元素
        array += ["cheese"]  // `+=` 操作符合并数组(要合并的两个数组类型必须一致)
        array.insert("coffee", at: 0) // 数组插入元素
        array.remove(at: 0) // 数组删除元素
        array.removeAll()          
        arr.removeAll(keepingCapacity: true) // 并且保留空间
        arr[0] = "q" // 修改,通过下标定位
    }

 15. 字典
    // 字典初始化
    var dict = ["a":"aa", "b":"bb"]
    var dict: Dictionary = ["a":"aa", "b":"bb"]
    var dict: Dictionary = ["a":"aa", "b":"bb"]

    // 字典 增/删/改
    dict["c"] = "cc" // 追加键值对 
    dict["a"] = "a"  // 修改
    dict.removeValue(forKey: "c") // 删除(直接给定 KEY)
    **`hash哈希`就是将字符串变成唯一的`整数`,便于查找,提高字典遍历的速度.而 KEY 便是hash MD5一种** 
   
    let vv = dict.removeValue(forKey: "c")  // "cc"
    print(vv!)        // "cc\n"-- 解包

    // 字典遍历
    for item in dict {  //dict.count)= 字典元素个数
        print(item)
    }
    for (key, value) in dict {
        print("\(key):\(value) ")
    }
    let keyArr = Array(dict.keys)
    let valueArr = Array(dict.values)

    // 字典合并(遍历)--不能像数组一样直接相加
    for (key, value) in dict1 {
        dict[key] = dict[value]
    }

 16. 函数
     /// 定义格式 
     func 函数名(形参列表) -> 返回值类型{
         ...  // 函数体
     }

     /// 没有返回值的函数(+无参) --> 主要用于闭包
     func printStar() ->Void {}  // Void
     func printStar() ->() {}    // ()
     func printStar() {}         // 直接省略


     /// 常量参数和变量参数
     1.默认都是`常量参数`,不能在函数内部修改.不同于C语言
      func test(num: Int)  相当于 func test(let num: Int)
     2.`变量参数`:需要在函数内部修改参数的值 (var)
      func test(var num: Int){ num = 10}


     /// 返回元组类型.
     func find(id: Int) -> (name: String ,age: Int){
         return ("小明", 20)
     }
     var person = find(1)
     print("name=\(person.name), age=\(person.age)")


     /// 有可变数量的参数,把参数看成一个数组
     func sumOf(numbers:Int...) -> Int {
        var sum = 0
        for number in numbers {
             sum += number
        }
        return sum
     }
     sumOf(42,597,12)


     /// 外部参数名
     1.写在形式参数名的前面,用空格隔开
     func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型{
          // 函数体
     }
     func find(stu_id id: Int) -> (name: String ,age: Int){
         return ("小明", 20)
     }
     find(stu_id: 1)

     2.用`#` 简化外部参数名的定义(外部参数名与参数名相同)
     func find(#id: Int) -> (name: String ,age: Int){
         return ("小明", 20)
     }
     find(id: 1)


     /// 默认参数值
     1.带有默认参数值的形参,Swift会自动给它生成一个跟形参名相同的外部参数名
     2.把带有默认参数名的参数名前面加个下划线`_`,调用函数时就不用写外部参数名 
     func addStudent (#name: String , age: Int = 20){ }
     addStudent (name: "小明")
     addStudent (name: "小红", age: 18)

 
    /// 输入输出函数 
    1.在C语言中,利用`指针`可以在函数内部修改外部变量的值
      void change (int * a){
          *a = 20; 
      }
      int num = 10;
      change(&num);

    2.在Swift中,利用`输入输出函数` ,也可以在函数内部改变`外部变量`的值
    --> 在参数名前面加个`inout`关键字即可
     func swap (inout num1: Int , inout num2: Int){
         var temp = num1;
         num1 = num2;
         num2 = temp; 
      }
      var a = 10
      var b = 20
      swap(&a, &b) // 传入的参数前面必须加 &


    /// 嵌入函数 ( 函数嵌套,相当于函数指针)
        函数可以被嵌套。里面的嵌套函数可以访问外面函数的变量。
        func chooseStepFunction(backwards: Bool) -> ((Int) -> Int){
            func stepForward(input: Int) -> Int{
                   return input + 1
            }
            func stepBackward(input: Int) -> Int{
                   return input - 1
            }
            return backwards ? stepBackward : stepForward
        }
        var currentValue = -4
        let moveNearerToZero = chooseStepFunction(backwards: currentValue > 0)
        while currentValue != 0 {
              print(currentValue)
              currentValue = moveNearerToZero(currentValue)
        }


     /// 函数是一个引用类型,就是说一个函数可以返回另一个函数作为返回值。
        func makeIncrementer() -> ( (Int)->Int ) {
             func addOne(number:Int) ->Int {
                 return 1+number
             }
             return addOne
        }
        var increment = makeIncrementer() // 返回的是addOne函数
        increment(7)


    /// 一个函数也可以用其他函数作为参数。
        func hasAnyMatches(list: [Int],condition:(Int)->Bool) -> Bool {
             for item in list {
                  if condition(item) {
                     return true
                 }
            }
            return false
       }
       func lessThanTen(number:Int) -> Bool {
            return number < 10
       }
       var number = [20, 19, 7, 12]
       hasAnyMatches(list: number,condition:lessThanTen)
   
 17. 闭包
     函数实际上是一种特殊的闭包,它是一段能之后被调取的代码。
     闭包中的代码能访问闭包所建作用域中能得到的变量和函数,即使闭包是在一个不同的作用域被执行的。 
     你可以使用{ }来创建一个匿名闭包。使用in将参数和返回值类型声明与闭包函数体进行分离。”

     - 类似于OC 的 block,但比block 应用面更广
       在 OC中 block 是匿名的函数
       在 Swift 中函数是特别的闭包

     - 应用场景
       异步执行完成回调
       控制器间回调
       自定义视图回调

     - 回调特点
       以参数回调处理结果
       返回值为 Void

    func closure() {
        
        // 1> 最简单的闭包
        // () -> () 没有参数和返回值的函数
        // 省略`() -> () in`
        let b1 = {
            print("hello")
        }
        // 执行闭包
        b1()
        
        // 2> 带参数的闭包
        // 闭包中,参数和返回值,实现代码写在{}里
        // 需要使用一个关键字`in`分隔定义和实现
        // {形参列表 -> 返回值  // 实现代码}
        let b2 = { (x: Int) -> () in
            print(x)
        }
        b2(100)
        
        // 3> 带参数/返回值的闭包
        let b3 = { (x: Int) ->Int in
            return x + 10
        }
        print(b3(100))     
     }
   
 18. GCD
    /**
     在异步执行任务,获取结果,通过 block/闭包 回调
     闭包的应用场景与 block 完全一致
     */
     func loadData(completion: @escaping (_ result: [String])->()) -> (){
        // 将任务添加到队列,指定执行任务的函数
        // 队列调度任务(block/闭包),以 同步/异步 的方式进行
        
        DispatchQueue.global().async {
            print("耗时操作\(Thread.current)") //耗时操作{number = 3, name = (null)}
            // 休眠
            Thread.sleep(forTimeInterval: 1.0)
            let json = ["aaa", "bbb"]
            
            // 主队列回调
            DispatchQueue.main.async {
                print("主线程更新 UI \(Thread.current)") //主线程更新 UI {number = 1, name = main}
                // 回调 -> 执行闭包(通过参数传递的)
                // 传递异步获取的结果
                completion(json)
            }
        }    
    }

   // `尾`随闭包
        // 如果函数的`最后一个参数`是闭包,函数参数可以提前结束,最后一个参数直接使用{}包装闭包的代码
        loadData(completion: {(result)->() in
            //原本的样式
        })
        loadData { (result) in
            print("获取的数据\(result)")
        }
    
 19.循环引用
   `循环引用` 单方向对引用是不会产生循环的
     - 闭包对 self 进行了 copy,闭包执行完成后会自动销毁,同时释放对 self 的引用
     - 同时 self 对闭包引用

    1> 哪种情况下会遇到循环引用:
      - 闭包中使用 self. 对当前对象强引用
      - 控制器(可以接收闭包的任意对象)以属性记录闭包(强引用)

    2> 三种解除闭包循环引用的方式
      (1)  OC 的方式:  weak var weakSelf = self
       - var, weak 只能修饰 var,不能修饰let
         weak可能会在运行时被修改 -> 只指向的对象一旦被释放,会被设置为 nil
       - ? 可选解包 - 如果self 已经被释放,不会向对象发送 getter 的消息,更安全
       - ! 强行解包 - 如果self 已经被释放,强行解包会导致崩溃 (需要计算的时候需要强行解包,因为可选项不能参与计算)

      (2)  Swift 推荐: [weak self]
           loadData2 {[weak self] in
              print(self?.view as Any)
           }
       - 表示闭包中的 self 是弱引用,如果 self 被释放,会自动设置为 nil
       - 与 OC 的__ weak 等效

      (3)  [unowned self]
           loadData2 {[unowned self] in
              print(self.view)
           }
       - 表示闭包中的 self 是 assign 的,不会强引用.但是,如果 self 被释放,指针地址保持不变,如果继续调用,会出现野指针的错误
       - 与 OC 的__ UN萨芬) unretained 等效

 20.命名空间 & 反射机制
    - 命名空间
      // 从 info.plist 中加载命名空间的名称
      let name = Bundle.main().infoDictionary?["CFBundleName"] as? String ?? "" 
     在Swift 中,默认同一个项目中(同一个命名空间下),所有的类都是共享的,可以直接访问,不需要 import
     所有对象的属性 var, 也可以直接访问到
     ps.第三方框架使用 Swift 如果直接拖拽到项目中,从属于同一个命名空间,很有可能冲突!----以后尽量都用 cocoaPod

    - 反射机制-----目的:为了解耦!
     对于任意一个类,都能够知道这个类的所有属性和方法
     对于任意一个对象,都能够调用它的任意一个方法和属性
     这种动态获取的信息以及动态调用对象的方法的功能称之为 Java 语言的反射机制
     eg. NSClassFromString、isMemberOfClass、isKindOfClass、conformToProtocol、respondsToSelecter、performSelect或 objc_msgSend间接调用 
  
        // AnyClass? -> 视图控制器的类型
        // 添加命名空间
        let cls = NSClassFromString("MaiXiaoJian_Swift.TabBarController") as? UITabBarController.Type
        let vc = cls?.init()
        window?.rootViewController = vc



 21.面向对象
    1>  构造函数基础(重写/重载)
        构造函数 (子类的构造过程与 OC 过程相反:子类 init-> 父类init)
        1. 构造函数的目的: 给自己的属性分配空间并设置初始值
        2. 调用父类构造函数之前,需要给本类的属性设置初始值
        3. 调用父类的`构造函数`,给父类的属性分配空间设置初始值
           NSObject 没有属性,只有一个成员变量`isa`
        4. 如果重载了构造函数,并且没有实现父类 init 方法,系统不再提供 init() 构造函数(默认是有的)
           因为:默认的构造函数不能给本类的属性分配空间

        * 不用写 func *
        * override重写(-父类存在相同的方法 -子类重新编写父类方法的实现) *
        * overload重载(-函数名相同 -参数类型和个数不同) *

    2>  KVC构造函数
        1. 定义模型属性的时候,如果是对象,通常都是可选的 var name: String?
           - 在需要的时候创建(延迟加载)
           - 避免写构造函数,可以简化代码
        2. 如果是基本数据类型,不可设置成可选的,而且要设置初始值,否则 KVC 会崩溃,运行时同样获取不到 var age: Int = 0
        3. 如果需要使用 KVC 设置数值,属性不可能是 private 的
        4. 使用 KVC 方法之前,应该调用 super.init 保证对象实例化完成!
               
            // 重载构造函数,使用字典为本类设置初始值
            init(dict: [String: AnyObject]) {
                super.init()  // 使用 self 的方法`setValuesForKeys`之前,应该调用 super.init
                setValuesForKeys(dict)
            }
              override func setValue(_ value: Any?, forUndefinedKey key: String) {
                    // 防止崩溃
               }
    3>  便利构造函数
        。。。。。。
        - 默认情况下

    4>  析构函数
        。。。。。。


 22.运行时
    使用`运行时`获取`当前类`所有属性的数组
    /// 获取 ivar 列表是所有第三方框架字典转模型的基础!
    class func propertyList() -> [String] {    
        var count: UInt32 = 0
        
        let list = class_copyPropertyList(self, &count)
        print("属性的数量\(count)")

        // 使用 guard 语法,一次判断每一项是否有值,只要有一项为 nil,就不再执行后面的代码
        for i in 0..只实现 getter 方法
      //本身不保存内容,都是通过计算获得结果
      //类似于一个函数/闭包(没有参数,一定有返回值)
      在 Swift 中只重写 getter 方法,不重写 setter 方法 
      var no: String? {
             get {
                 return _no //简写: 省略 get {}  直接 return
             }
      }

    - `计算型`属性:执行函数返回其他内存地址(属性本身不占用内存空间;不可以给其设置数值)
      `存储型`属性:需要开辟空间,以数据存储

    - 计算型属性 & 懒加载属性 对比
    * 计算型属性
       /**
        不分配独立的存储空间保存计算结果
        每次调用时都会被执行
        更像一个函数,不过不能接收参数,同时必须有返回值
        var title: String {
          return "Mr"+(name ?? " ")
        }
        // MARK:计算型属性返回
        var namespace1: String {
              return infoDictionary?["CFBundleName"] as? String ?? ""
        }
        */
     * 懒加载属性
       /**
        在第一次调用时,执行闭包并且分配空间存储闭包返回的数值
        会分配独立的存储空间
        与 OC 不同的是,lazy 属性即使被设置为 nil也不会被再次调用
        lazy var title:String {
            return "lazy"+(self.name ?? " ")
        }
        */

 25.重写 setter 方法 :`didSet`
    var person: Person? {    
        didSet {
            text = person?.name
        }
    }

 26.MVVM(引用规则:View|Controller → ViewModel → Model,反向不行)
    - view 和 viewController 正式联系在一起,我们把它视作一个组件
    - view 和 viewController 都不能直接引用 model,而是引用viewModel
    - viewModel 是一个封装业务逻辑处理、视图显示逻辑、网络处理、数据缓存

三方库:
pod 'SnapKit', '~> 0.20.0' ## 自动布局
pod 'Alamofire', '~> 3.3.1' ## 网络请求, swift版的AFN
pod 'Kingfisher', '~> 2.3.1' ## 轻量级的SDWebImage

你可能感兴趣的:(Swift 3.0 学习笔记)