Swift备忘录

 

Swift 备忘录 2015-4

 

一、简介

 

1、Swift 语言由苹果公司在2010年7月开始设计,在 2014 年6月推出,在 2015 年 12 月 3 日开源 

 

2、特点(官方):

 

(1)苹果宣称 Swift 的特点是:快速、现代、安全、互动,而且明显优于 Objective-C 语言

(2)可以使用现有的 Cocoa 和 Cocoa Touch 框架

(3)Swift 取消了 Objective-C 的指针及其他不安全访问的使用

(4)舍弃 Objective-C 早期应用 Smalltalk 的语法,全面改为句点表示法

(5)提供了类似 Java 的名字空间(namespace)、泛型(generic)、运算对象重载(operator overloading)

(6)Swift 被简单的形容为 “没有 C 的 Objective-C”(Objective-C without the C)

 

3、强语法规范以及一些注意点

 

(1)空格的使用(对比OC)

 

(2)数据类型的异常严格的要求

 

(3)不用导入头文件,使用pod时例外

 

 

二、常量变量

 

1、 let :定义常量,一经赋值不允许再修改

       var: 定义变量,赋值之后仍然可以修改

 

使用技巧:优先选择 let 定义常量/变量, Xcode7.0以后如果变量没有修改,会给出警告,提示使用let代替var

 

 

2、未赋值的常量有一次赋值的机会,例:

let x1: Int

x1 = 30

 

3、关于自动推导

 

(1)swift 可以根据右边的类型准确推导出变量的类型,例如  var num  = “张三”  ,num就是一个字符串类型

 

(2)开发中一般不用指定变量类型

 

(3)如果要指定,跟在后面,例如  var num : String = “张三”

 

4、option + 左键点击  的使用:查看变量的类型

 

5、没有隐式转换,不同数据类型间的运算,必须统一数据类型(显式强转换),例:

 

let x2 = 100

let y2 = 10.5

let num1 = Double(x2) + y2

let num2 = x2 + Int(y2)

 

Optional 可选类型

 

1、定义:swift一大特色,表示一个变量的值可以是nil,也可以是一个指定的值。

 

2、表示方式:在类型后面加? 例如: var num : Int ?

 

3、被设置成可选类型的变量,默认值是nil

 

4、被设置成可选类型的常量,没有默认值,其意义也不大,例:

let url = NSURL(string: "http://www.baidu.com")

let num: Int? = 10

 

 

关于可选项的解包判断是否为nil

 

1、不可参与运算&&可以打印:如果 Optional 值是 nil,不允许参与计算,只有解包(unwrap)后才能参与计算,但是解包前是可以打印的

 

2、解包方式:

(1)在变量后添加一个 !     可以强行解包

      注意:必须要确保解包后的值不是 nil,否则会报错 

例(错误提示):unexpectedly found nil while unwrapping an Optional value

 

(2)简单的 if 判断,但还是需要使用到强行解包

if url != nil {

    let request = NSURLRequest(URL: url!)

}

 

(3)使用 if let 、guard let等特殊处理方式

 

(4)可选链,使用一个 ?给对象进行 “弱” 解包,有值则正常返回,无值则返回nil

 

(5)空合并运算符??

 

3、避免强解包造成崩溃、不使用强制解包————> 详解

 

(1)if  let 判断

例:如果可选项num为空,则不执行if分支的代码,也就不会崩溃

if let n = num {

    let r = n + 10

}

 

(2)where子句  

语义:如果判断的条件不止一个,判断的条件具备从属关系,又要避免多层的(难看的)嵌套if,可以使用where 

if let 不能与 &&、|| 等条件判断方式一同使用,如果要增加条件,可以使用 where 子句(where 子句没有智能提示)

例:

if let u = url where u.host == "www.baidu.com" {

    let request = NSURLRequest(URL: u)

}

 

 

(3) guard 判断,与 if  let 语义相反,Swift 2.0 推出 (在真正的逻辑代码部分,可以省掉一层嵌套)

语义:如果变量为nil 则执行 分支中的代码 。  

例:

 

let oName: String? = "张三"

let oNum: Int? = 18

 

guard let name = oName else {

    return

}

 

guard let num = oNum else {

    return

}

 

// 代码如果能执行至此,name & num 都是一定不为nil的,此处也没有if let中的嵌套(少了一层),随便写~~

print(name)

print(num)

 

 

(4)空合并运算符 ?? 

语义:如果为nil,则使用??后面的值代替,简化了代码,例如:

let num: Int? = nil

let r1 = (num ?? 0) + 10

print(r1)

 

(5)多个可选类型判断(避免多个可选项为nil)

方法:可以使用 “  ,” 同时判断多个可选类型是否为空

let oName: String? = "张三"

let oNo: Int? = 100

if let name = oName, let no = oNo {

    print("姓名:" + name + " 学号: " + String(no))

}

 

(6)可选链 “  ?”的使用,对比 “  !” 

语义:如当对象为可选类型时,对其属性的访问,要先解包,但如果使用!,有可能因为nil造成崩溃,这时可以使用?,如果对象存在,则解包调用,如果对象为nil则不进行后续操作。

例:

        var p : person?

        let  name  = (p?.name) ?? ""

        print(name)

 

控制流

 

1、if 的注意点:

 

(1)没有OC中非零及真的概念

(2)明确显式的指出 true  或  false 进行逻辑判断

(3)()可以省略,{}不可以省略

 

2、三目运算符与OC相同

 

3switch(变化很大)

 

(1)switch 不再局限于整数, 可以针对任意数据类型进行判断

  示例:

let score = "优"

switch score {

case "优":

    let name = "学生"

    print(name + "80~100分")

case "良": print("70~80分")

case "中": print("60~70分")

case "差": print("不及格")

default: break

}

 

(2)可以省略 break

 

(3)每一个 case后面必须有可以执行的语句,不能什么都不写

 

(4)要保证处理所有可能的情况,不然编译器直接报错,不处理的条件可以放在 default (不可省)分支中

 

(5)每一个 case 中定义的变量仅在当前 case 中有效,而 OC 中需要使用 {},swift可以省略

 

(6)同样有穿透,使用关键字 fallthrough,只穿透一层, 而且case语句中不能定义变量或常量

 

(7)switch 中同样能够赋值和使用 where 子句

  示例:

let point = CGPoint(x: 10, y: 10)

switch point {

case let p where p.x == 0 && p.y == 0:

    print("中心点")

case let p where p.x == 0:

    print("Y轴")

case let p where p.y == 0:

    print("X轴")

case let p where abs(p.x) == abs(p.y):

    print("对角线")

default:

    print("其他")

}

 

(8)如果只希望进行条件判断,赋值部分可以省略,使用 _  ,  表示“不关心”

示例:

switch score {

case _ where score > 80: print("优")

case _ where score > 60: print("及格")

default: print("其他")

}

 

 

 

循环

 

1、for 循环

 

(1)仿OC写法 ,()可以省略

var sum = 0

for var i = 0; i < 10; i++ {

    sum += i

}

print(sum)

 

(2)for - in  写法 

语义  :在一个范围(或集合中)循环遍历出每个个体 ,例:

  • 范围 0..< 10 表示从0到9 , i 就是 0、1、2 ……9 的个体,一个循环10次,,对比0...10

sum = 0

for i in 0..<10 {

    sum += i

}

print(sum)

 

  • 遍历子控件集合,打印每一个子控件

 

     for myView in view.subviews {      

       print(myView)

        }

 

 

(3)for - in 省略下标写法

语义:忽略_ 对应位置的值

for _ in 0...10 {

    print("hello")

}

 

2、do - while 循环

(1)swift2.0以后把do-while 改成了repeat- while

例:

      var index = 3

      repeat {

          index--

          print(index)

      } while index > 0

 

3、while 循环,和OC一样,可以省略()

 

 

字符串

 

1、结构体类型 Sting

 

(1)let 定义不可变字符串

 

(2)var 定义可变字符串

 

(3)定义空字符串:

var a: String = String()

 

2、与NSString比较:

 

(1)String 是一个结构体,性能更高,具有了绝大多数 NSString 的功能

 

(2)String 支持直接遍历

 

(3)NSString 是一个 OC 对象,性能略差

 

(4)Swift 提供了 String 和 NSString 之间的无缝转换

 

3、遍历字符串(characters属性)

示例:

for s in str.characters {

    print(s)

}

 

4、字符串长度

 

(1)返回以字节为单位的字符串长度,一个中文占 3 个字节,根据编码方式

let len1 = str.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)

 

(2) 返回实际字符的个数

let len2 = str.characters.count

 

(3) 返回 utf8 编码长度

let len3 = str.utf8.count

 

 

5字符串拼接

(1)直接在 "" 中使用 \(变量名) 的方式可以快速拼接字符串

let str1 = "Hello"

let str2 = "World"

let i = 32

str = "\(i) 个 " + str1 + " " + str2

 

(2)可选项的拼接,如果变量是可选项,拼接的结果中会有 Optional字符,使用空合并运算符

let str1 = "Hello"

let str2 = "World"

let i: Int? = 32

str = "\(i ?? 0) 个 " + str1 + " " + str2

 

(3)格式化字符串

        在实际开发中,如果需要指定字符串格式,可以使用 String(format:...) 的方式

 

let h = 8

let m = 23

let s = 9

let timeString = String(format: "%02d:%02d:%02d", arguments: [h, m, s])

let timeStr = String(format: "%02d:%02d:%02d", h, m, s)

 

6、截取字符串(复杂一些) 

 

关键词 : startIndex、endIndex、startIndex.advancedBy、substringToIndex、substringWithRange

 

例:

首先定义常量 :  let str = "hello"

 

(1)占位符  + substring  方式   

 

//”hel"只是一个占位字符串,可以随便写,   startIndex 是光标的开始索引

        let startIndex = "hel".startIndex

        let endIndex = "hel".endIndex

        

//从起点开始一直截取到末尾

        let result = str.substringFromIndex(startIndex)

 

//截取到结束位数

        let result1 = str.substringToIndex(endIndex)

 

       

(2) advancedBy + range  方式

 

        //advancedBy 如果传入的是正数则是往后加多少为

        let strStartIndex = str.startIndex.advancedBy(1)

        let strEndIndex = str.endIndex.advancedBy(-1)

        let result2 = str.substringWithRange(strStartIndex..<strEndIndex)

        

(3)转成OC + range 方式

 

        let result3 = (str as NSString).substringWithRange(NSMakeRange(1, str.characters.count-2))

let.result4=(str as NSString).substringWithRange(NSMakeRange(2, 3))

 

 

 

 

数组

 

1、定义、获取元素与OC相同

例:

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let num1 = numbers[0]

 

2、let 、var 区分可变和不可变数组

 

3、遍历使用 for - in ,例:

 

for num in numbers {

    print(num)

}

 

4、追加元素、删除元素

 

array1.append(“张三”)

 

array1.removeAtIndex(3)

 

array1.removeAll()

 

5、数组的定义和实例化

 

(1)使用  :   可以只定义数组的类型 , 例:

var array: [String]

 

(2)实例化之前不允许添加值

 

(3)使用 [类型]() 可以实例化一个空的数组 ,例:

array = [String]()

array.append(“老王”)

 

6、数组的类型

 

(1)如果初始化时,所有内容类型一致,则数组中保存的是该类型的内容,后续添加的元素必须类型一致

 

(2)如果初始化时,所有内容类型不一致,则数组中保存的是 NSObject

 

(3)swift 中 数字可以直接加入集合中,不用包成NSNumber

 

(4)swift 中 将结构体添加到集合中,还是需要包成NSValue,例:

array.append(NSValue(CGPoint: CGPoint(x: 10, y: 10)))

 

7、数组的合并

 

(1)必须是相同类型的数组才能够合并

(2)开发中,通常数组中保存的对象类型都是一样的!

 

8、内存分配

(1)如果向数组中追加元素,超过了容量,会直接在现有容量基础上 * 2,例:

 

var list = [Int]()

for i in 0...16 {

    list.append(i)

    print("添加 \(i) 容量 \(list.capacity)")

}

 

一个奇怪的现象:添加第一个元素时,数组容量为 2

 

(2)数组移除元素后,保持容量

 

 

字典

 

1、定义字典

 

(1)使用 [ ]   : var dict = ["name": "zhangsan", "age": 18]

 

(2)var dict : [String : NSObject] = [String : NSObject]( )

dict[key] = value

 

 

2、最常用的类型  

 

(1)[String : NSObject] 

 

(2)AnyObject 的范围要比NSObject大

 

3、赋值

(1)赋值直接使用 dict[key] = value 格式

(2)如果 key 不存在,会设置新值

(3)如果 key 存在,会覆盖现有值

 

4、遍历

(1)使用(key,value)+  for-in 的方式,key,value可以随便写

(2)前面的是 key,后面的是 value

    例:

for (k, v) in dict {

    print("\(k) ~~~ \(v)")

}

 

5、增删改,例:

 

(1)增、改:如果key不存在,则进行添加,如果key存在,则进行修改

  var dic1 = ["name": “老王”,”age": 18]     

dic1["sex"] = "男"

    dic1["name"] = “老李”

 

(2)删

        dic1["age"] = nil

        dic1.removeValueForKey("name")

        

(3)改

        dic1.updateValue(28, forKey: "age")

        

 

6、合并字典

(1)如果 key 不存在,会建立新值,否则会覆盖现有值

 

var dict1 = [String: NSObject]()

dict1[“nickname"] = "大老虎"

dict[“age"] = 100

for (k, v) in dict1 {

    dict[k] = v

}

print(dict)

 

 

 

 

函数

 

1、函数的定义

(1)格式 func 函数名(行参列表) -> 返回值 {代码实现}

 

(2)调用 let result = 函数名(值1, 参数2: 值2...)

 

2、没有返回值的函数,一共有三种写法

(1)省略

(2)—> ()

  (3)  —>Void

 

3、外部参数

(1)在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义

 

(2)格式:func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型 { // 代码实现 }

例:

func sum1(num1 a: Int, num2 b: Int) -> Int {

    return a + b

}

 

sum1(num1: 10, num2: 20)

 

(3)Swift 2.0 中,默认第一个参数名省略

 

(4)闭包中也有外部参数

 

4、swift 可以在函数中定义函数,函数也可以作为其他函数的参数

 

 

十一闭包

 

1、定义:闭包类似于 OC 中的 Block

 

(1)预先定义好的代码块

 

(2)在需要时执行

 

(3)可以像变量一样当作参数传递

 

(4)可以像函数一样有返回值

 

(5)包含 self 时需要注意循环引用

 

 

2、作用:与 OC 中的 Block 类似,闭包主要用于异步操作执行完成后的代码回调,网络访问结果以参数的形式传递给调用方

 

3、格式:闭包 = { (行参) -> 返回值 in // 代码实现 },例:

 

let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in

    return x + y

}

sumFunc(num1: 10, num2: 20)

 

  最简单的闭包,直接就是 闭包 = {代码实现 }

 

4、尾随闭包:函数的最后一个参数是一个闭包,则小括号可以提前关闭,闭包放在小括号外面

 

5、 如果函数的参数只有一个闭包,函数的小括号可以省略,例:

 

loadData { (result:String) -> () in

                       

print(result)

 

    }

 

6、闭包回调简单应用示例

 

(1)  override func viewDidLoad() {

        super.viewDidLoad()

       

    //  调用带有闭包作为参数的函数(尾随闭包效果)

 

        loadData() { (result) -> () in

            print(result)

        }

    }

    

 

(2)  //  函数需要传入一个闭包 闭包的类型是有参数无返回值得闭包

 

    func loadData(callbackClosure: (result: String) -> ()) {

        

        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in

            

            //  模拟耗时操作

            NSThread.sleepForTimeInterval(2)

            

            let result = "办证:137xxxx"

            

            dispatch_async(dispatch_get_main_queue(), { () -> Void in

                

                callbackClosure(result: result)

                

            })

            

        }

        

    }

 

 

 

十二闭包的循环引用

 

1、原因,类似于OC中的block:

 

  <1> OC中

 

(1)对象A 有一个 block 的属性, self 通过调用A的方法,将定义好的block 传递给对象A ,说明对象A 引用了这个block

 

(2)对象A 又作为 self 的一个属性, 说明 self 引用了对象A

 

(3)block 中出现 self , 说明这个block 引用了 当前 self 

 

(4)到此 : 引用循环形成

 

  <2> swift中(最简单的循环引用)

 

(1)闭包中 出现self , 说明闭包持有(引用)了self

 

(2)self 中 定义了这个闭包,说明self 引用了这个闭包

 

2、示例

 

(1)“全局”的闭包变量

 

var closure: (()->())?

 

(2)给闭包赋值,并且在闭包中引用了self

 

    override func viewDidLoad() {

        super.viewDidLoad()

        

        closure = { 

            

            dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in

                NSThread.sleepForTimeInterval(2)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                      print(self.view)

                })

            })

 

        }

        

        closure?()

}

 

(3)循环形成

 

3、解决

 

 <1> OC中

(1)使用弱引用,破除环

 

(2)iOS5.0 推出:__weak typeof(self) weakSelf = self;

 

(3)iOS4.0 推出:__unsafe_unretained typeof(self) weakSelf = self;

 

(4)区别:__unsafe_unretained 如果当前对象self销毁后,weakSelf执行的地址不变,而这个地址对应对象已经销毁了,所以再去访问该对象就崩溃,形成野指针了,相当于assign。然而前者在self销毁后,会自动把weakSelf的地址设置成nil,所以不会有野指针

 

 

 <2> swift中

 

(1)仿OC写法:

 

  weak var weakSelf = self

 

(2)swift写法:

 

        [weak self] 相当于 之前__weak 对象销毁后 self指向的地址为nil

        [unowned self] 相当于 之前的 __unsafe_retain  对象销毁后 self执行的地址不变

      

        

        closure = { [unowned self] in

            //  判断weakSelf是否有值,如果有值则执行,否则直接返回nil

            

            dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in

                NSThread.sleepForTimeInterval(2)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                      print(self.view)

                })

            })      

        }

        closure?()

    }

 

(2)析构函数,对象释放后会执行这个函数,类比OC的dealloc

 

    deinit {

 

        //  移除通知

        //  移除kvo

        //  移除NSTimer

        

        print("ViewController over")

    }

 

 

十三构造函数

 

1、定义:是一种特殊的函数,主要用来:

 

(1)在创建对象时初始化对象

 

(2)为对象成员变量设置初始值

 

2、和OC的对比:

 

(1)在 OC 中的构造函数是 initWithXXX,在 Swift 中由于支持函数重载,所有的构造函数都是 init,不用写func

 

(2)构造函数的作用

分配空间 alloc

设置初始值 init

3、必选属性

1非可选属性就是必选属性

2如果一个类中定义了必选属性,必须通过构造函数为这些必选属性分配空间并且设置初始值

4Optional 可选属性

(1)可选属性不需要设置初始值,默认初始值都是 nil

 

(2)可选属性是在设置数值的时候才分配空间的,是延迟分配空间的,更加符合移动开发中延迟创建的原则

(3)注意,普通数据类型如Int,在设置为可选,并且没有初始化时,也是nil,在与OC的交互中就会出问题,因为OC的普通类型都有初始值,比如Int = 0 ,所以要根据情况,给可选属性初始化。。。  这种情况出问题的,比如KVC给模型属性赋值。

 

5override init() 方法的特殊性  (其中有些争议)

(1)先给自己的必选属性赋值

(2)再调用super.init()初始化父类的属性

(3)其他重载的构造函数不是这个顺序,要先调用super实例化对象,再给自己的必选属性赋值

4关于系统提供的默认构造函数Xcode 7 beta 5之后,父类的构造函数会被自动调用(也就是说,可以不用写super.init()),强烈建议写 super.init(),保持代码执行线索的可读性(这里应该是只有父类系统会自动调用。。)

(5)重载的构造函数,系统不会调用默认构造函数  ( 这句话有待商榷,实验中,也是调了,个人感觉,只要是继承自NSObject的父类,系统都会帮我们调默认的构造函数,而子类就不会,因为默认的构造函数满足不了需求)

 

 

十四、重载与重写

1、重载定义:

 

(1)面向对象的一个重要特征,oc里面没有

 

(2)函数名相同,参数名或者参数个数不同就是重载,不仅限于构造函数

 

 (3) 函数重载能够简化程序员的记忆

 

2、重写定义:

 

(1)必须有继承关系的函数,对父类函数功能的重写和完善

 

(2)override关键字

 

3、注意事项

(1)如果重载了构造函数,但是没有实现默认的构造函数 init(),则系统不再提供默认的构造函数。原因,在实例化对象时,必须通过构造函数为对象属性分配空间和设置初始值,对于存在必选参数的类而言,默认的 init() 无法完成分配空间和设置初始值的工作(这里也是有待商榷,实验证明,父类不管是否实现 init(),重载了构造函数,系统依然会调用默认的构造函数)

(2)在子类中,如果是重载的构造函数,必须 super 以完成父类属性的初始化工作

(3)重写时,子类需要在父类拥有方法的基础上进行扩展,需要 override 关键字,父类没有方法,重写不了!

(4)重写的是构造方法时,也要注意super一下,除非你是父类,系统帮你super.init(这是实验结果)

 

十五、KVC构造函数

1、KVC本质

(1)KVC 是 OC 特有的,KVC 本质上是在运行时,动态向对象发送 setValue:ForKey: 方法,为对象的属性设置数值

(2)在使用 KVC 方法之前,需要确保对象已经被正确实例化

 

2、关于基本数据类型

(1)在 Swift 中,如果属性是可选的,在初始化时,不会为该属性分配空间

 

(2)OC 中基本数据类型就是保存一个数值,不存在可选的概念,比如Int 默认是0,不是nil

 

(3)使用KVC进行属性赋值时,如果基本数据类型的属性没有初始化,就会报错,所以,需要初始化一个数值

报错举例:this class is not key value coding-compliant for the key age. ->这个类的键值 age 与 键值编码不兼容

 

3KVC 函数调用顺序

  (1) setValuesForKeysWithDictionary 会按照字典中的 key 重复调用 setValue(value, forKey) 函数

 

  (2) 如果没有实现 forUndefinedKey 函数,程序会直接崩溃,NSObject 默认在发现没有定义的键值时,会抛出 NSUndefinedKeyException 异常

       如果实现了 forUndefinedKey,会保证 setValuesForKeysWithDictionary 继续遍历后续的 key

 

  (3) 如果父类实现了 forUndefinedKey,子类可以不必再实现此函数

 

(4)补充:setValue(value, forKeyPath) 这个方法默认也是调用 setValue(value, forKey),不要在后者中去实现前者,否则死循环

 

(5)如果实现setValue(value, forKey)方法,不要忘记super

 

4、补充:通过KVC给只读属性赋值,例:自定义tabBar

   

     //自定义tabBar    

     let tab = ZQTabBarView()

        

     //使用kvc,给readonly属性赋值

        

     setValue(tab, forKey: "tabBar")

        

 

 

 

 

十六convenience 便利构造函数

 

1、定义

1)可以返回nil的构造函数(可失败的构造函数)

2)有关键字convenience

3)不能被重写

4)不能使用super

5)使用self 来调用自己的其他指定构造函数,比如:self.init()

6init后面有?

 

2指定构造函数

1默认情况下,所有的构造方法都是指定构造函数 Designated

 

(2)除了便利构造函数

 

3示例    (在 Xcode 中,输入 self.init 时没有智能提示)

convenience init?(name: String, age: Int) {

    if age < 20 || age > 100 {

        return nil

    }

 

    self.init(dict: ["name": name, "age": age])

}

 

4便利构造函数应用场景

(1)根据给定参数判断是否创建对象,而不像指定构造函数那样必须要实例化一个对象出来

(2)在实际开发中,可以对已有类的构造函数进行扩展,利用便利构造函数,简化对象的创建

 

5、再次注意

(1)指定构造函数必须调用其直接父类的的指定构造函数(除非没有父类,系统调),也就是必须调一下指定构造函数

 

(2)便利构造函数可以返回 nil

 

(3)便利构造函数不能被重写

 

(4)便利构造函数必须调用同一类中定义的其他指定构造函数,如果自己没有指定构造函数,则用 self. 的方式调用父类的便利构造函数,再或者通过self.的方式调用父类的指定构造函数(子类从父类继承)

 

 

6、图示:(子类便利构造函数调用父类便利构造函数的情况没有描述)

 

Pasted Graphic.tiff

 

 

 

十七懒加载

 

1、意义如同OC中的懒加载,swift懒加载本质上是一个闭包,在使用的时候才会创建

 

2、懒加载的格式:关键字  lazy

 

(1)闭包写法:定义一个闭包,并执行了,这里语句  “ ()-> Person in” 省略了,只有懒加载可以

 

lazy var person: Person = {

    return Person()

}()

 

(2)同上

let personFunc = { () -> Person in

    return Person()

}

lazy var demoPerson: Person = self.personFunc()

 

(3)懒加载的简单写法 :定义个变量,前面加上lazy

lazy var demoPerson: Person = Person()

 

3、注意:与 OC 不同的是,lazy 属性即使被设置为 nil 也不会被再次调用

 

 

 

 

十八只读属性和重写set方法

 

1、swift的 set和get方法

(1)在 Swift 中 getter & setter 很少用

(2)示例:

private var _name: String?

var name: String? {

    get {

        return _name

    }

    set {

        _name = newValue

    }

}

 

3)经常使用的重写set方法

    var person: Person? {

        didSet {

            nameLabel.text = person?.name

            ageLabel.text = "\(person?.age ?? 0)"

        }

    }

 

 

2存储型属性

1需要开辟空间,以存储数据

 

3、计算型属性(只读)

1执行函数返回其他内存地址

(2)只实现 getter 方法的属性被称为计算型属性,等同于 OC 中的 ReadOnly 属性

var title: String {

    get {

        return "Mr " + (name ?? "")

    }

}

简写

var title: String {

    return "Mr " + (name ?? "")

}

(3)计算型属性本身不占用内存空间

(4)不可以给计算型属性设置数值

5)只读型更像一个函数,不过不能接收参数,同时必须有返回值

(6)每次调用时都会被执行,这里和懒加载不同

 

 

十八、网络访问(不使用AFN

1、同OC ,在iOS7.0以后,默认使用https,要设置白名单(ATS)强制访问

<key>NSAppTransportSecurity</key>

<dict>

  <!--Include to allow all connections (DANGER)-->

  <key>NSAllowsArbitraryLoads</key>

      <true/>

</dict>

 

 

2、JSON的反序列化:与OC略不同

 

 (1)try! 向系统保证我的数据一定是一个json

 

       let result = try! NSJSONSerialization.JSONObjectWithData(data, options: [])

    

(2) try? 如果是json就反序化成功,否则直接返回nil

 

       let result = try? NSJSONSerialization.JSONObjectWithData(data, options: [])

           

(3) try catch   判断序列化的时候是否出现异常,如果有异常则进入catch,否则反序列化成功

           

do {

          let result = try NSJSONSerialization.JSONObjectWithData(d, options: [])

                print(result)

         } catch {

                print(error)

         }

 

 

十九swift使用pod

 

1、如同OC正常安装pod

 

2、在podfile文件中贴入(可以使用vim编辑器),第一行不可少,使用OC框架可以不用桥接(不知道什么鬼。。)

 

use_frameworks!

platform :ios, '8.0'

 

pod 'SDWebImage'

pod 'SVProgressHUD'

pod 'SnapKit'

pod 'FMDB'

pod 'AFNetworking'

 

 

 

二十swiftOC 的桥接

 

1、正常情况下,swift想要使用oc的文件需要桥接

 

2、步骤:

 

(1)创建一个 header.h 文件(要求和 info.plist同级)

 

(2)找到bridge的配置路径,把 header.h路径放入配置文件里:

 

配置文件步骤  buildSettings - > 查找bridge  - > 设置路径(和info.plist同级)

 

(3)到 header.h 文件里 ,导入 OC框架的头文件,需要哪个导入哪个

   

 

 

二十一extension description

 

1、extension 类似于 OC 的 Category,可以按照函数类型区分代码,能够让代码结构具有更好的可读性

2、重写 description 属性(只读属性),便于调试。 在类中定义如下,将成员属性作为key传入,然后打印这个类的对象就可以显示出准确内容

例:
override var description: String {

  let keys = ["name", "age"]

    return dictionaryWithValuesForKeys(keys).description

}

 

 

二十二、自定义DEBUG

1、如同OC中的PCH文件,设置自定义的DEBUG,可以随时调整关闭DEBUG

2、步骤

(1)创建swift file 文件

(2)贴入下面内容

/// 输出日志

 

/// - parameter message:  日志消息

 

/// - parameter logError: 错误标记,默认是 false,如果是 true,发布时仍然会输出

 

/// - parameter file:     文件名

 

/// - parameter method:   方法名

 

/// - parameter line:     代码行数

 

func printLog<T>(message: T,

        logError: Bool = false,

    file: String = __FILE__,

    method: String = __FUNCTION__,

    line: Int = __LINE__)

{

    if logError {

             print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")

    } else {

        

#if DEBUG

            print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")

        #endif

    }

}

 

(3)配置:buildingSetting  -> 查找 swift flags  - >在下方设置debug标记  - >    点击加号  ->  添加  :  -D DEBUG

(4)程序发布前,删掉 DEBUG即可

(5)另外,在此文件中定义的变量、常量,可以全局访问,类似PCH文件

 

二十三、SpanKit 和 SVProgressHUD 的使用

1、SpanKit用来进行页面布局的三方控件(约束),等同于OC中的 masnory

示例

      registerButton.snp_makeConstraints { (make) -> Void in

            make.left.equalTo(noticeLabel.snp_left)

            make.top.equalTo(noticeLabel.snp_bottom).offset(10)

 

            make.width.equalTo(100)

            make.height.equalTo(30)

        }

 

2、SVProgressHUD 简单使用

示例

func webViewDidStartLoad(webView: UIWebView) {

    SVProgressHUD.show()

}

 

func webViewDidFinishLoad(webView: UIWebView) {

    SVProgressHUD.dismiss()

}

///  关闭

func close() {

    SVProgressHUD.dismiss()

    dismissViewControllerAnimated(true, completion: nil)

}

 

posted @ 2016-04-07 23:12  执着的怪味豆  阅读(377)  评论(0编辑  收藏  举报