1.typealias
//聲明一個閉包類型 AddBlock
typealias AddBlock = (Int,Int)->(Int);
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let add:AddBlock = {
(a,b) in
return a + b;
}
let result = add(1100, 200);
print("result=(result)");
} }
2.escaping
逃逸閉包一般用于異步函數的回調,比如網絡請求成功的回調和失敗的回調。語法:在函數的閉包行參前加關鍵字“@escaping” ((Any?)->(Void))?,也可以表示網絡請求成功的回調,不過后面需帶“?”,這代表閉包可選類,這并不是閉包類型的,兩者對比如下:
可選閉包
func requestData(urlString:String,succeed: ((Any?)->(Void))?,failure:((Any?)->(Void))?){}
逃逸閉包
func requestData(urlString:String,succeed: @escaping (Any?)->(Void),failure:@escaping (Any?)->(Void)){}
注意
如果是在閉包內部調用控制器,那么必須顯示的寫self。防止閉包帶來的循環引用的問題
如何解決閉包的循環引用, 同樣有三種方式:
使用weak修飾變量, 打破強引用, 因為使用weak修飾的變量有一次變成nil的機會
使用[weak self] 修飾閉包原理跟__weak類似, 這樣在閉包中使用self, 就是弱引用
使用[unowned self ] 修飾閉包, 跟__unsafe_unretained類似, 不安全
eg:
// 解決方式一: weak
weak var weakSelf = self
loadData { (dataString) -> () in
print("(dataString) (weakSelf?.view)")
}
//解決方式二: 在swift中 有特殊的寫法 ,跟OC __weak 相似 [weak self]
loadData { [weak self] (dataString) -> () in
//以后在閉包中中 使用self 都是若引用的
print("\(dataString) \(self?.view)")
}
//解決方式三: [unowned self] 跟 _unsafe_unretained 類似 不推薦使用
loadData { [unowned self] (dataString) -> () in
print("(dataString) (self.view)")
}
}
3.兩個訪問關鍵字介紹(fileprivate、open)
flieprivate
fileprivate 其實就是過去的 private。其修飾的屬性或者方法只能在當前的 Swift 源文件里可以訪問。即在同一個文件中,所有的 fileprivate 方法屬性都是可以訪問到的。
class A {
fileprivate func test(){
print("this is fileprivate func!")
}
}
class B:A {
func show(){
test()
}
}
而private現在變為了真正的私有訪問控制。就是說不管在不在同一個文件中,用private修飾的方法也不可以被代碼域之外的地方訪問。
class A {
private func printA(){
print("A")
}
}
class B:A {
func printB(){
printA()
}
}
上面的實例是我們使用private方法定義一個父類A的成員方法,但是當繼承該類的子類調用該方法時將會報錯
open
過去public有兩個作用:
修飾的屬性或者方法可以在其他作用域被訪問;
修飾的屬性或者方法可以在其他作用域被繼承或重載override。
但這樣就會有問題,為了安全,我們可能希望某個類或屬性能夠被外部訪問,但又不想其被繼承或修改。如果將其標記成final后又會造成任何地方都不能被override。比如對lib設計者來說,他希望的結果是在module內可以被override,而被import 到外部后不能被override。 現在新添加的open起的就是原來public的作用。而現在的public表示在其他module中不可以被override和繼承,而在module內可以被 override和繼承
5種修飾符訪問權限排序
從高到低排序如下:
open> public > interal > fileprivate > private
4.Designated,Convenience 和 Required
在 Objective-C 中,init 方法是非常不安全的:沒有人能保證 init 只被調用一次,也沒有人保證在初始化方法調用以后實例的各個變量都完成初始化,甚至如果在初始化里使用屬性進行設置的話,還可能會造成各種問題,雖然 Apple 也明確說明了不應該在 init 中使用屬性來訪問,但是這并不是編譯器強制的,因此還是會有很多開發者犯這樣的錯誤。
所以 Swift 有了超級嚴格的初始化方法。一方面,Swift 強化了 designated 初始化方法的地位。Swift 中不加修飾的 init 方法都需要在方法中保證所有非 Optional 的實例變量被賦值初始化,而在子類中也強制 (顯式或者隱式地) 調用 super 版本的 designated 初始化,所以無論如何走何種路徑,被初始化的對象總是可以完成完整的初始化的。
class ClassA {
let numA: Int
init(num: Int) {
numA = num
}
}
class ClassB: ClassA {
let numB: Int
override init(num: Int) {
numB = num + 1
super.init(num: num)
}
}
在上面的示例代碼中,注意在 init 里我們可以對 let 的實例常量進行賦值,這是初始化方法的重要特點。在 Swift 中 let 聲明的值是常量,無法被寫入賦值,這對于構建線程安全的 API 十分有用。而因為 Swift 的 init 只可能被調用一次,因此在 init 中我們可以為常量進行賦值,而不會引起任何線程安全的問題。
與 designated 初始化方法對應的是在 init 前加上 convenience 關鍵字的初始化方法。這類方法是 Swift 初始化方法中的 “二等公民”,只作為補充和提供使用上的方便。所有的 convenience 初始化方法都必須調用同一個類中的 designated 初始化完成設置,另外 convenience 的初始化方法是不能被子類重寫或者是從子類中以 super 的方式被調用的。
class ClassA {
let numA: Int
init(num: Int) {
numA = num
}
convenience init(bigNum: Bool) {
self.init(num: bigNum ? 10000 : 1)
}
}
class ClassB: ClassA {
let numB: Int
override init(num: Int) {
numB = num + 1
super.init(num: num)
}
}
只要在子類中實現重寫了父類 convenience 方法所需要的 init 方法的話,我們在子類中就也可以使用父類的 convenience 初始化方法了。比如在上面的代碼中,我們在 ClassB 里實現了 init(num: Int) 的重寫。這樣,即使在 ClassB 中沒有 bigNum 版本的 convenience init(bigNum: Bool),我們仍然還是可以用這個方法來完成子類初始化:
let anObj = ClassB(bigNum: true) anObj.numA //10000 anObj.numB //10001
因此進行一下總結,可以看到初始化方法永遠遵循以下兩個原則:
初始化路徑必須保證對象完全初始化,這可以通過調用本類型的 designated 初始化方法來得到保證;
子類的 designated 初始化方法必須調用父類的 designated 方法,以保證父類也完成初始化。
對于某些我們希望子類中一定實現的 designated 初始化方法,我們可以通過添加 required 關鍵字進行限制,強制子類對這個方法重寫實現。這樣做的最大的好處是可以保證依賴于某個 designated 初始化方法的 convenience 一直可以被使用。一個現成的例子就是上面的 init(bigNum: Bool):如果我們希望這個初始化方法對于子類一定可用,那么應當將 init(num: Int) 聲明為必須,這樣我們在子類中調用 init(bigNum: Bool) 時就始終能夠找到一條完全初始化的路徑了:
class ClassA {
let numA: Int
required init(num:Int) {
numA = num
}
convenience init(bigNum: Bool) {
self.init(num: bigNum ? 10000 : 1)
}
}
class ClassB:ClassA {
let numB: Int
required init(num: Int) {
numB = num + 1
super.init(num: num)
}
}
另外需要說明的是,其實不僅僅是對 designated 初始化方法,對于 convenience 的初始化方法,我們也可以加上 required 以確保子類對其進行實現。這在要求子類不直接使用父類中的 convenience 初始化方法時會非常有幫助。
4.final
可以通過把方法,屬性或下標標記為final來防止它們被重寫,只需要在聲明關鍵字前加上final修飾符即可(例如:final var,final func,final class func,以及final subscript)。如果你重寫了final方法,屬性或下標,在編譯時會報錯。
5.static和class的區別
在方法的func關鍵字之前加上關鍵字static或者class都可以用于指定類方法. 不同的是用class關鍵字指定的類方法可以被子類重寫, 如下:
override class func work() {
print("Teacher: University Teacher")
}
但是用static關鍵字指定的類方法是不能被子類重寫的, 根據報錯信息: Class method overrides a 'final' class method. 我們可以知道被static指定的類方法包含final關鍵字的特性--防止被重寫.
這是我自己總結的,如有不對,望指出