Block總結(jié)以及內(nèi)存管理

之前只知道Block不使用屬性copy的話,Block位于棧內(nèi)存,方法調(diào)用過后,再次調(diào)用Block的話,會出現(xiàn)EXC_BAD_ACCESS(野指針)錯(cuò)誤,還有使用Block容易出現(xiàn)循環(huán)引用問題。具體再細(xì)節(jié)一點(diǎn)的話就不知道了,現(xiàn)在這里再梳理一邊關(guān)于Block的知識。

block 結(jié)構(gòu)體信息詳解

struct __block_impl

// __block_impl 和 __main_block_desc_0 是 block 實(shí)現(xiàn)的兩個(gè)結(jié)構(gòu)體
// 可以說Block的本質(zhì)是指向結(jié)構(gòu)體的指針,但是因?yàn)開_block_impl有
// isa指針,指向?qū)嵗龑ο?,也可以說Block是一個(gè)Objective-C對象
// (這里具體去看isa指針和Runtime機(jī)制了解一下)

struct __main_block_impl_0
{
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0)
    {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};
struct __block_impl
{
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};
  1. Block對象和一般對象的區(qū)別:
    Block對象與一般的類實(shí)例對象有所不同,一個(gè)主要的區(qū)別就是分配的位置不同,block默認(rèn)在棧上分配,一般類的實(shí)例對象在堆上分配。Block將使用到的、作用域附近到的變量的值建立一份快照拷貝到棧上。

  2. Block類型以及它們的區(qū)別:

  • NSGlobalBlock:類似函數(shù),位于text段
    這里的Block沒有對周圍變量引用
  • NSStackBlock:位于棧內(nèi)存,函數(shù)返回后Block將無效
    這里的Block引用了周圍變量(沒有使用copy屬性)
  • NSMallocBlock:位于堆內(nèi)存。
    NSStackBlock類型使用Block_copy()或者發(fā)送了copy消息,就會被放到堆上面,變成NSMallocBlock類型。在某個(gè)方法中實(shí)例化一個(gè)Block,在ARC環(huán)境下會被默認(rèn)放到堆上面
    float (^sum)(float, float) = ^(float a, float b){
        return a + b;
    };
    
    NSArray *testArray = @[@"1", @"2"];
    
    void (^testBlock)(void) = ^{
        NSLog(@"%@", testArray);
    };
    
    NSLog(@"Global Block:%@",sum);
    
    NSLog(@"Stack Block:%@", ^{NSLog(@"%@", testArray);});
    
    NSLog(@"Malloc Block:%@", testBlock);
Demo[1187:67028] Global Block:<__NSGlobalBlock__: 0x106d85330>
Demo[1187:67028] Stack Block:<__NSStackBlock__: 0x7fff58f557e0>
Demo[1187:67028] Malloc Block:<__NSMallocBlock__: 0x7fe2d2ca66d0>
  1. Block屬性操作:
  • Block不管是retain、copy、release都不會改變引用計(jì)數(shù)retainCount,retainCount始終是1
  • NSGlobalBlock:retain、copy、release操作都無效;
  • NSStackBlock:retain、release操作無效,必須注意的是,NSStackBlock在函數(shù)返回后,Block內(nèi)存將被回收。即使retain也沒用。容易犯的錯(cuò)誤是[[mutableAarry addObject:stackBlock],在函數(shù)出棧后,從mutableAarry中取到的stackBlock已經(jīng)被回收,變成了野指針。(在arc中不用擔(dān)心此問題,因?yàn)閍rc中會默認(rèn)將實(shí)例化的block拷貝到堆上)
  • NSMallocBlock支持retain、release,雖然retainCount始終是1,但內(nèi)存管理器中仍然會增加、減少計(jì)數(shù)。copy之后不會生成新的對象,只是增加了一次引用,類似retain。
  1. Block外部變量存取操作
  • 局部變量Block中只讀,Block定義時(shí)copy變量的值,在Block中作為常量使用。(這里的局部變量傳入一個(gè)Block里面的同名變量,所以不能改變局部變量的值)
  • STATIC修飾符的全局變量,因?yàn)槿肿兞炕蜢o態(tài)變量在內(nèi)存中的地址是固定的,Block在讀取該變量值的時(shí)候是直接從其所在內(nèi)存讀出,獲取到的是最新值,而不是在定義時(shí)copy的常量(這里傳入的全局變量或者靜態(tài)變量,傳入的是指向該內(nèi)存的指針,所以就算外部修改,在Block里面也是通過指針的值取變量的值)
  • Block變量,被__block修飾的變量稱作Block變量。 基本類型的Block變量等效于全局變量、或靜態(tài)變量。
    注:BLOCK被另一個(gè)BLOCK使用時(shí),另一個(gè)BLOCK被COPY到堆上時(shí),被使用的BLOCK也會被COPY。但作為參數(shù)的BLOCK是不會發(fā)生COPY的

參考來源:
深入理解Objective-C的Block
iOS學(xué)習(xí)之block總結(jié)及block內(nèi)存管理(必看)
block沒那么難(一):block的實(shí)現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Block簡介(copy一段) Block作為C語言的擴(kuò)展,并不是高新技術(shù),和其他語言的閉包或lambda表達(dá)式是...
    qui丶MyLove閱讀 494評論 0 0
  • 使用block已經(jīng)有一段時(shí)間了,感覺自己了解的還行,但是幾天前看到CocoaChina上一個(gè)關(guān)于block的小測試...
    心愿2016閱讀 376評論 0 0
  • 前言 Blocks是C語言的擴(kuò)充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,881評論 0 23
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場景。SDWebImage的原...
    LZM輪回閱讀 2,129評論 0 12
  • 農(nóng)村冬天的夜晚和城市很不一樣。 下午四點(diǎn)剛過,天空便顯出倦怠的神色,不那么亮堂,若還飄著點(diǎn)雨,樹、草、園子里...
    風(fēng)吹過_fd4e閱讀 214評論 0 0

友情鏈接更多精彩內(nèi)容