Swift 閉包(二)

OC Block 和 Swift 閉包相互調(diào)用

我們在 OC 中定義的 Block雁乡,在 Swift 中是如何調(diào)用的呢橄镜?我們來看一下

typedef void(^ResultBlock)(NSError *error); 

@interface LGTest : NSObject

+ (void)testBlockCall:(ResultBlock)block; 

@end

Swift 中我們可以這么使用

LGTest.testBlockCall{ error in
    let errorcast = error as NSError
    print(errorcast) 
}

func test(_ block: ResultBlock){
    let error = NSError.init(domain: NSURLErrorDomain, code: 400, userIn: nil) 
    block(error)
}

比如我們在 Swift 里這么定義,在 OC 中也是可以使用的

class LGTeacher: NSObject{
    @objc static var closure: (() -> ())?
}
+ (void)test{
    // LGTeacher.test{}
    LGTeacher.closure = ^{ 
        NSLog(@"end");
    };
}
LGTest.test() 
LGTeacher.closure!()

@convention 關(guān)鍵字介紹

@convention:用于修飾函數(shù)類型

  • 修飾 Swift 中的函數(shù)類型(調(diào)用 C 函數(shù)的時候)
  • 調(diào)用 OC 方法時剂癌,修飾 Swift 函數(shù)類型

defer 的用法

定義:defer {} 里的代碼會在當前代碼塊返回的時候執(zhí)行麦乞,無論當前代碼塊是從哪個分支 return 的,即使程序拋出錯誤十嘿,也會執(zhí)行。

  • 案例 1

如果多個 defer 語句出現(xiàn)在同一作用域中岳锁,則它們出現(xiàn)的順序與它們執(zhí)行的順序相反绩衷,也就是先出現(xiàn)的后執(zhí)行。

  • 案例 2
func append(string: String, terminator: String = "\n", toFileAt url: URL) throws {
    // The data to be added to the file
    let data = (string + terminator).data(using: .utf8)!
    let fileHandle = try FileHandle(forUpdating: url)

    defer {
        fileHandle.closeFile()
    }
    
    // If file doesn't exist, create it
    guard FileManager.default.fileExists(atPath: url.path) else {
        try data.write(to: url)
        return
    }
    
    // If file already exists, append to it
    fileHandle.seekToEndOfFile()
    fileHandle.write(data)
}

let url = URL(fileURLWithPath: NSHomeDirectory() + "/Desktop/swift.txt")
try append(string: "iOS開發(fā)語言", toFileAt: url)
try append(string: "Swift", toFileAt: url)

這里有時候如果當前方法中多次出現(xiàn) closeFile激率,那么我們就可以使用 defer咳燕。

  • 案例 3
let count = 2
let pointer = UnsafeMutablePointer<Int>.allocate(capacity: count)
pointer.initialize(repeating: 0, count: count)
defer {
    pointer.deinitialize(count: count)
    pointer.deallocate()
}

在我們使用指針的時候,allocatedeallocate乒躺,initializedeinitialize 都是成對出現(xiàn)的招盲,這時候我們就可以將 deallocatedeinitialize 放到 defer {} 中。

  • 案例 4
func netRquest(completion: () -> Void) {
    defer {
        self.isLoading = false
        completion()
    }
    guard error == nil else { return }
}

比如我們在進行網(wǎng)絡請求的時候嘉冒,可能有不同的分支進行回調(diào)函數(shù)的執(zhí)行曹货,這個時候可以使用 defer {} 來管理 completion 回調(diào),前提是這里是非異步的讳推,defer {} 就是方便我們來管理代碼塊控乾。

defer 使用注意

使用 defer 的時候要避免像這樣書寫,編譯器也會提示 defer 可能不會立即執(zhí)行娜遵。

這里需要注意的是 temp 的值還是 1,因為 defer {} 是在返回之后執(zhí)行壤短。其實這里 defer 這樣使用并沒有意義设拟,我們要避免這樣的寫法,defer 我們要用來管理一些統(tǒng)一資源久脯, 優(yōu)化冗余代碼纳胧, 使代碼更加簡潔直觀。

逃逸閉包

逃逸閉包:當閉包作為一個實際參數(shù)傳遞給一個函數(shù)的時候帘撰,并且是在函數(shù)返回之后調(diào)用跑慕,我們就說這個閉包逃逸了。當我們聲明一個接受閉包作為形式參數(shù)的函數(shù)時摧找,你可以在形式參數(shù)前加上 @escaping 來明確閉包是允許逃逸的核行。

  • 作為函數(shù)的參數(shù)傳遞
  • 當前閉包在函數(shù)內(nèi)部異步執(zhí)行或者被存儲
  • 函數(shù)結(jié)束,閉包被調(diào)用蹬耘,生命周期結(jié)束

注意:可選類型默認是逃逸閉包芝雪!

  • 使用場景 1
class CXTeacher {
    var completionHandle: ((Int) -> Void)?
    
    func makeIncrementer(_ amout: Int, handler: @escaping (Int) -> Void) {
        var count = 10
        count += amout
        
        completionHandle = handler
    }
    
    func dosomething() {
        makeIncrementer(20) {
            print($0)
        }
    }
}

let t = CXTeacher()
t.dosomething()
t.completionHandle?(10) 

這里是定義了一個 completionHandle 屬性,在 makeIncrementer 函數(shù)中將閉包參數(shù) handler 賦值給 completionHandle综苔,這時候閉包的生命周期比 makeIncrementer 函數(shù)的生命周期要長惩系,我們可以在需要的時機調(diào)用閉包位岔,這個時候這個閉包就是逃逸閉包。

  • 使用場景 2
class CXTeacher {
    var completionHandle: ((Int) -> Void)?
    
    func makeIncrementer(_ amout: Int, handler: @escaping (Int) -> Void) {
        var count = 10
        count += amout
        
        DispatchQueue.global().asyncAfter(deadline:  .now() + 0.1) {
            handler(count)
        }
    }
    
    func dosomething() {
        makeIncrementer(20) {
            print($0)
        }
    }
}

let t = CXTeacher()
t.dosomething()
t.completionHandle?(10)

這里是在原函數(shù)中異步執(zhí)行閉包堡牡,這個時候閉包的生命周期也比原函數(shù)要長抒抬,這時候 handler 也是逃逸閉包。

非逃逸閉包

func testNoEscaping(_ f: () -> Void) {
    f()
}

func test() -> Int {
    var age = 18
    testNoEscaping {
        age += 20
    }

    return 30
}

test()

這個就是一個非逃逸閉包晤柄,當函數(shù)調(diào)用完之后這個閉包也就消失了擦剑。并且非逃逸閉包還有以下優(yōu)點:

  • 不會產(chǎn)生循環(huán)引用,函數(shù)作用域內(nèi)釋放
  • 編譯器會做更多性能優(yōu)化 (retain可免、relsase)
  • 上下文的內(nèi)存保存在棧上抓于,不是堆上
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浇借,隨后出現(xiàn)的幾起案子捉撮,更是在濱河造成了極大的恐慌,老刑警劉巖妇垢,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巾遭,死亡現(xiàn)場離奇詭異,居然都是意外死亡闯估,警方通過查閱死者的電腦和手機灼舍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涨薪,“玉大人骑素,你說我怎么就攤上這事「斩幔” “怎么了献丑?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長侠姑。 經(jīng)常有香客問我创橄,道長,這世上最難降的妖魔是什么莽红? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任妥畏,我火速辦了婚禮,結(jié)果婚禮上安吁,老公的妹妹穿的比我還像新娘醉蚁。我一直安慰自己,他們只是感情好柳畔,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布馍管。 她就那樣靜靜地躺著,像睡著了一般薪韩。 火紅的嫁衣襯著肌膚如雪确沸。 梳的紋絲不亂的頭發(fā)上捌锭,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音罗捎,去河邊找鬼观谦。 笑死,一個胖子當著我的面吹牛桨菜,可吹牛的內(nèi)容都是我干的豁状。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倒得,長吁一口氣:“原來是場噩夢啊……” “哼泻红!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起霞掺,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谊路,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后菩彬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缠劝,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年骗灶,在試婚紗的時候發(fā)現(xiàn)自己被綠了惨恭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡耙旦,死狀恐怖脱羡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情免都,我是刑警寧澤轻黑,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站琴昆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏馆揉。R本人自食惡果不足惜业舍,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望升酣。 院中可真熱鬧舷暮,春花似錦、人聲如沸噩茄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绩聘。三九已至沥割,卻和暖如春耗啦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背机杜。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工帜讲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椒拗。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓似将,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚀苛。 傳聞我的和親對象是個殘疾皇子在验,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容