日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OC语言Block 续

發(fā)布時(shí)間:2023/12/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OC语言Block 续 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

OC語(yǔ)言 Block

轉(zhuǎn)載:http://blog.csdn.net/weidfyr/article/details/48138167

1.Block對(duì)象中的變量行為

結(jié)論:

  • 在block代碼塊內(nèi)部可以訪問定義的全局變量,局部變量,靜態(tài)局部變量,但是訪問局部靜態(tài)變量時(shí)候是只讀的并且局部變量和在代碼塊中訪問到的不是同一個(gè)地址的變量,他們?cè)跀?shù)值上相等,互相似乎沒什么聯(lián)系。 因?yàn)榇a塊中使用到局部變量的時(shí)候,會(huì)將局部變量進(jìn)行const類型的copy,所以在代碼塊中訪問到的局部變量都是只讀的;靜態(tài)變量和全局變量都存放在靜態(tài)區(qū),在程序運(yùn)行過程中都存在,他們可以在不同的代碼塊中共享,不同代碼塊中訪問到的同一個(gè)全局變量,局部變量是同一塊內(nèi)存的數(shù)據(jù);對(duì)于普通局部變量在代碼塊中只讀,全局變量和靜態(tài)局部變量在代碼塊中可以讀寫。

  • 在塊句法的主體中,除塊句法內(nèi)部的局部變量和形參之外,還包含塊句法當(dāng)前位置處可以訪問的變量;這些變量中包含外部變量也包含塊中可以訪問的局部變量。

  • 代碼塊中訪問局部變量時(shí)候,局部變量會(huì)從棧內(nèi)存被const類型的copy一份到堆內(nèi)存中。

  • 塊對(duì)象和函數(shù)指針的定義使用功能都差不多,塊對(duì)象的精髓之處就在于,在塊對(duì)象中可以訪問到上下文的變量,而函數(shù)指針不能。

    2.塊對(duì)象的實(shí)例和生命周期

    • 1)塊句法也可以寫在函數(shù)的外部,當(dāng)寫在函數(shù)外面時(shí)候,只是在靜態(tài)數(shù)據(jù)區(qū)分配一塊內(nèi)存給塊對(duì)象,這塊區(qū)域在程序執(zhí)行期間會(huì)一直存在。
    • 2)塊句法寫在函數(shù)內(nèi)部的時(shí)候,塊對(duì)象和變量的生命周期和普通局部變量一樣,塊對(duì)象的內(nèi)存區(qū)域會(huì)在執(zhí)行包含塊對(duì)象的函數(shù)時(shí)保存在棧上;該塊對(duì)象的生命周期就是函數(shù)運(yùn)行期間。
    • 3)在現(xiàn)實(shí)的實(shí)現(xiàn)中,當(dāng)函數(shù)內(nèi)的塊語(yǔ)法不包含自動(dòng)變量的時(shí)候,就沒必要進(jìn)行復(fù)制值,所以塊對(duì)象的內(nèi)存區(qū)域也會(huì)被保存在靜態(tài)數(shù)據(jù)區(qū)。
    • 4)block代碼塊被保存在堆或者靜態(tài)區(qū)中,不會(huì)被保存在棧中,如下圖可以說明這一點(diǎn)。

    示例
    - (void)function {int i;int (^blocks[10])(); //定義一個(gè)塊對(duì)象類型的數(shù)組for (i = 0; i < 10; i++) { //for循環(huán)給數(shù)組賦值blocks[i] = ^{ return i; };}for (i = 0; i < 10; i++) { //打印數(shù)組中的內(nèi)容,就是每個(gè)數(shù)組存放的代碼塊的返回值NSLog(@"%d", blocks[i]());} } // 如上代碼,在非ARC環(huán)境下運(yùn)行結(jié)果是10個(gè)9,原因是雖然循環(huán)了十次,但是只有一個(gè)實(shí)體。 // 以上代碼在ARC環(huán)境下是正確的,后面做說明。

    3.塊對(duì)象的復(fù)制

    • 函數(shù)內(nèi)的塊對(duì)象和局部變量的生命周期相同,都只是在函數(shù)的執(zhí)行期間。但是在函數(shù)的方法調(diào)用參數(shù)中直接代入塊對(duì)象也是塊對(duì)象的一種非常常見的用法,這時(shí)候使用與函數(shù)調(diào)用關(guān)系或棧狀態(tài)無關(guān)的塊對(duì)象是非常必要的。
    • 有一個(gè)函數(shù)可以復(fù)制塊對(duì)象到新的堆內(nèi)存,通過使用該函數(shù),即使是在函數(shù)內(nèi)部定義的塊對(duì)象也能獨(dú)立于棧被持續(xù)的使用,此外還有一個(gè)函數(shù)可以釋放不需要的塊對(duì)象。

    Block_copy( block )

    • 1.參數(shù)為棧上的塊對(duì)象的時(shí)候,返回堆上的塊對(duì)象。參數(shù)為堆上的塊對(duì)象或者靜態(tài)區(qū)的塊對(duì)象,不進(jìn)行復(fù)制,直接返回原對(duì)象,但是會(huì)增加參數(shù)塊對(duì)象的引用計(jì)數(shù)。

    Block_release( block )

    • 2.減少參數(shù)塊對(duì)象的引用計(jì)數(shù)。當(dāng)引用計(jì)數(shù)減到0時(shí)候,塊對(duì)象被釋放。
    • 3.在使用這些函數(shù)的時(shí)候,需要引入頭文件Block.h .堆上的塊對(duì)象使用引用計(jì)數(shù)的方式來管理。即使使用垃圾回收也必須成對(duì)出現(xiàn)。使用ARC時(shí)候可以不考慮這些,編譯器會(huì)自動(dòng)幫我們判斷什么時(shí)候釋放,什么時(shí)候保持。
    // 用法示例: g = Block_copy(block); Block_rlease(g);

    4.指定特殊變量 __block

    • ARC下測(cè)試結(jié)果和總結(jié):

    • 非ARC下測(cè)試結(jié)果和總結(jié):

    使用block時(shí)候注意事項(xiàng):

    使用注意事項(xiàng):

    • 1)在塊內(nèi)改變外部變量的值時(shí)候,在外部變量前加__block,否則該值在block塊內(nèi)部是只讀的。
    • 2)在引用某個(gè)實(shí)例變量或者所在控制器本身時(shí)候,在ARC下,要再前面加__weak如:__weak (typeof(self) weak self = self), 在mrc下用__block, 這樣做是為了避免內(nèi)存泄露和循環(huán)引用。
    • 3)在使用block前需要對(duì)block指針做判空處理,如果是MRC的編譯環(huán)境下,要先release掉block對(duì)象。
    • 4)在MRC的編譯環(huán)境下,block如果作為成員參數(shù)要copy一下將棧上的block拷貝到堆上(因?yàn)閎lock默認(rèn)是在棧上創(chuàng)建的,如果在定義block的作用于外部使用block那么需要使用copy將block放到堆上)//MRC下:_sucBlock = [callbackBlock copy]; 不copy block會(huì)在棧上被回收。
    • 5)將block賦值為空,是解掉循環(huán)引用的重要方法。
    • 6)還有一種改法,在block接口設(shè)計(jì)時(shí),將可能需要的變量作為形參傳到block中,從設(shè)計(jì)上解決循環(huán)引用的問題。
    • 7)在多線程環(huán)境下(block中的weakSelf有可能被析構(gòu)的情況下),需要先將self轉(zhuǎn)為strong指針,避免在運(yùn)行到某個(gè)關(guān)鍵步驟時(shí)self對(duì)象被析構(gòu)。
      第四、第五條合起來有個(gè)名詞叫weak–strong dance,來自于2011 WWDC Session #322 (Objective-C Advancements in Depth)

    • 以下代碼來自AFNetworking,堪稱使用weak–strong dance的經(jīng)典。

    __weak __typeof(self)weakSelf = self;AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); }};
    • Review一下上面這段代碼,里面玄機(jī)不少。

      • 第一行:__weak __typeof(self)weakSelf = self;
      • 如之前第四條所說,為防止callback內(nèi)部對(duì)self強(qiáng)引用,weak一下。
      • 其中用到了__typeof(self),這里涉及幾個(gè)知識(shí)點(diǎn):
    • a. __typeof、typeof、typeof的區(qū)別
      • 恩~~他們沒有區(qū)別,但是這牽扯一段往事,在早期C語(yǔ)言中沒有typeof這個(gè)關(guān)鍵字,__typeof、__typeof__是在C語(yǔ)言的擴(kuò)展關(guān)鍵字的時(shí)候出現(xiàn)的。
      • typeof是現(xiàn)代GNU C++的關(guān)鍵字,從Objective-C的根源說,他其實(shí)來自于C語(yǔ)言,所以AFNetworking使用了繼承自C的關(guān)鍵字。
    • b.對(duì)于老的LLVM編譯器上面這句話會(huì)編譯報(bào)錯(cuò),所以在很早的ARC使用者中流行__typeof(&*self)這種寫法,
      • 原因如下大致說法是老LLVM編譯器會(huì)將__typeof轉(zhuǎn)義為 XXX類名 *const __strong的__strong和前面的__weak關(guān)鍵字對(duì)指針的修飾又沖突了,所以加上&*對(duì)指針的修飾。

      • 第三行:__strong __typeof(weakSelf)strongSelf = weakSelf;
        按照之前第五條的說法給轉(zhuǎn)回strong了,這里__typeof()里面寫的是weakSelf,里面寫self也沒有問題,因?yàn)閠ypeof是編譯時(shí)確定變量類型,所以這里寫self 不會(huì)被循環(huán)引用。

      • 第四、五、六行,如果不轉(zhuǎn)成strongSelf而使用weakSelf,后面幾句話中,有可能在第四句執(zhí)行之后self的對(duì)象可能被析構(gòu)掉,然后后面的StausBlock沒有執(zhí)行,導(dǎo)致邏輯錯(cuò)誤。

      • 最后第五行,使用前對(duì)block判空。

    轉(zhuǎn)載于:https://www.cnblogs.com/ShaoYinling/p/7821457.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的OC语言Block 续的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。