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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Block 再学习 !

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

如何優(yōu)雅的使用 Block?

How Do I Declare A Block in Objective-C?

阮一峰的一句話解釋簡(jiǎn)潔明了:閉包就是能夠讀取其它函數(shù)內(nèi)部變量的函數(shù)

詳情:http://blog.csdn.net/jasonblog/article/details/7756763

block的幾種適用場(chǎng)合:

  • 任務(wù)完成時(shí)回調(diào)處理
  • 消息監(jiān)聽回調(diào)處理
  • 錯(cuò)誤回調(diào)處理
  • 枚舉回調(diào)
  • 視圖動(dòng)畫、變換
  • 排序

作為基本變量 As a?local variable

1 returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

作為對(duì)象屬性 As a?property

1 @property (nonatomic, copy) returnType (^blockName)(parameterTypes);

作為方法參數(shù) As a?method parameter

1 - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

作為回調(diào) As an argument to a?method call:

1 [someObject someMethodThatTakesABlock:^returnType (parameters) {...}];

作為類型別名 As atypedef

1 2 typedef returnType (^TypeName)(parameterTypes); TypeName blockName = ^returnType(parameters) {...};

?

什么是Block

  • Block是iOS中一種比較特殊的數(shù)據(jù)類型
  • 是一個(gè)能工作的代碼單元,可以在任何需要的時(shí)候被執(zhí)行
  • 本質(zhì)是輕量級(jí)的匿名函數(shù),可以作為其他函數(shù)的參數(shù)或者返回值。
  • Block是蘋果官方特別推薦使用的數(shù)據(jù)類型, 應(yīng)用場(chǎng)景比較廣泛
    • 動(dòng)畫
    • 多線程
    • 集合遍歷
    • 網(wǎng)絡(luò)請(qǐng)求回調(diào)
  • Block的作用
    • 用來保存某一段代碼, 可以在恰當(dāng)?shù)臅r(shí)間再取出來調(diào)用
    • 功能類似于函數(shù)和方法
1 2 //Block 是對(duì) C 語(yǔ)言的一個(gè)拓展 //快速創(chuàng)建 Block 用 inlineBlock

Block的格式

  • Block的定義格式
1 2 3 返回值類型 (^block變量名)(形參列表) = ^(形參列表) { };

  • block最簡(jiǎn)單形式(無(wú)參無(wú)返回值)
1 2 3 4 5 6 void (^block)() = ^{代碼塊;} 例如: void (^myBlock)() = ^{ NSLog(@"Damonwong"); };
  • block中級(jí)進(jìn)階形式(有參無(wú)返回值)
1 2 3 4 5 6 7 void (^block名稱)(參數(shù)列表) = ^ (參數(shù)列表) { // 代碼實(shí)現(xiàn); } 例如: void (^myBlock)(int) = ^(int num){ NSLog(@"num = %i", num); };
  • block高級(jí)進(jìn)階形式(有參有返回值)
1 2 3 4 5 6 7 返回類型 (^block名稱)(參數(shù)列表) = ^ 返回類型 (參數(shù)列表) { // 代碼實(shí)現(xiàn); } 例如: int (^myBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; };
  • 調(diào)用Block保存的代碼
1 block變量名(實(shí)參);

?

Block 與 變量

觀察下面四段代碼的輸出值

  • Block 可以讀取變量,但是默認(rèn)情況下不能修改變量的值
1 2 3 4 5 6 7 8 int x = 123; void (^printXAndY)(int) = ^(int y) { x = 100; //會(huì)報(bào)錯(cuò), printf("%d %d\n", x, y); }; printXAndY(456); /*------------------*/ @"prints: 123 456"
  • Block 能讀取變量的原理是 「copy」了一份變量的值。所以在 Block 定義之后修改變量的值,再調(diào)用 Block,值依舊是修改前的。換句話說,定義好 Block 之后,修改變量值對(duì) Block 無(wú)效。
1 2 3 4 5 6 7 8 int x = 123; void (^printXAndY)(int) = ^(int y) { printf("%d %d\n", x, y); }; x = 456; // 修改 x 為 456,block 依舊輸出 123 printXAndY(456); /*------------------*/ @"prints: 123 456"
  • __blcok關(guān)鍵字的神奇功效。

首先,如果需要對(duì)block 外部定義的變量在 block 內(nèi)修改,那么需要對(duì)這個(gè)變量添加一個(gè)__block修飾。

1 2 3 4 5 6 7 8 __block int x = 123; void (^printXAndY)(int) = ^(int y) { x = 100; //不會(huì)報(bào)錯(cuò) printf("%d %d\n", x, y); }; printXAndY(456); /*------------------*/ @"prints: 100 456"

如果需要在調(diào)用之前,變量的修改都會(huì)影響 block 內(nèi)部對(duì)這個(gè)變量的使用,換句話說,block 對(duì)變量不再是簡(jiǎn)單的值復(fù)制,而是動(dòng)態(tài)的"監(jiān)聽"值的變化,然后在調(diào)用的時(shí)候讀取變量的值。需要對(duì)這個(gè)變量添加一個(gè)__block修飾。

1 2 3 4 5 6 7 8 __block int x = 123; void (^printXAndY)(int) = ^(int y) { printf("%d %d\n", x, y); }; x = 456 //block 會(huì)「動(dòng)態(tài)」識(shí)別外部變量的變化,輸出456 printXAndY(456); /*------------------*/ @"prints: 456 456"
  • 注意區(qū)別變量和指針?biāo)赶虻淖兞?/li>
1 2 3 4 5 6 7 8 int x = 123; NSMutableString *str = [NSMutableString stringWithFormat:@"Damon"]; void (^printStr)() = ^() { [str appendString:@"wong"]; NSLog(@"%@",str); }; printStr(); // prints:Damonwong

這里的?[str appendString:@"wong"];不報(bào)錯(cuò)是因?yàn)閟tr 是指向@"Damon"的函數(shù)指針,[str appendString:@"wong"];并不是修改 str 存儲(chǔ)的值,本質(zhì)上是 str 向@"Damon"發(fā)送了一條appendString 消息,然后再更改@"Damon"為@"Damonwong",而 str 存儲(chǔ)的指向@"Damonwong"對(duì)象的指針沒有發(fā)生變化。所以,block 本質(zhì)是不能修改變量存儲(chǔ)的值,但是消息分發(fā)依舊有效。


?


?

?

Block 的循環(huán)引用問題

雖然 Block 用起來特別方便,但是要特別注意循環(huán)應(yīng)用的問題。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // ARC enabled /************** MyObject Class **************/ typedef void (^myBlock)(void); @interface MyObject : NSObject { myBlock block; } @end @implementation MyObject - (id)init { self = [super init]; block = ^{ NSLog(@"self = %@", self); }; return self; } - (void)dealloc { NSLog(@"dealloc"); } @end /************** main function **************/ int main() { id myObject = [[MyObject alloc] init]; NSLog(@"%@", myObject); return 0; }

由于 self 是 __strong 修飾,在 ARC 下,當(dāng)編譯器自動(dòng)將代碼中的 block 從棧拷貝到堆時(shí),block 會(huì)強(qiáng)引用和持有 self,而self 恰好也強(qiáng)引用和持有了 block,就造成了傳說中的循環(huán)引用。

為了避免這種情況發(fā)生,可以在變量聲明時(shí)用?__weak修飾符修飾變量 self,讓 block 不強(qiáng)引用 self,從而破除循環(huán)。

1 2 3 4 5 6 7 8 9 - (id)init { self = [super init]; __weak typeof(self) weak_self = self; block = ^{ NSLog(@"self = %@", weak_self); }; return self; }

黑科技,防止循環(huán)引用

1 2 3 4 5 6 7 8 9 10 11 - (id)init { self = [super init]; __block typeof(self) temp = self; block = ^{ NSLog(@"self = %@", temp); temp = nil; }; return self; } // 使用這個(gè),必須調(diào)用一次 block

Tips

  • 宏定義:#define Weak_Ref(obj)?_weak typeof(obj) weak##obj = obj;

  • 注意self.name這類點(diǎn)語(yǔ)法,[self name]消息傳遞及?self。

  • block 中使用 self不一定造成循環(huán)引用,但可能性極大

  • 重寫?dealloc?方法可以很方便的知道是否存在循環(huán)引用

?

?

Block 在內(nèi)存中的位置

由于block也是NSObject,我們可以對(duì)其進(jìn)行retain操作。不過在將block作為回調(diào)函數(shù)傳遞給底層框架時(shí),底層框架需要對(duì)其copy一份。比方說,如果將回調(diào)block作為屬性,不能用retain,而要用copy。我們通常會(huì)將block寫在棧中,而需要回調(diào)時(shí),往往回調(diào)block已經(jīng)不在棧中了,使用copy屬性可以將block放到堆中。或者使用Block_copy()和Block_release()。

  • 根據(jù)Block在內(nèi)存中的位置分為三種類型
    • NSGlobalBlock:類似函數(shù),位于text段,全局的靜態(tài) block,不會(huì)訪問任何外部變量
    • NSStackBlock :保存在棧中的 block,當(dāng)函數(shù)返回時(shí)會(huì)被銷毀
    • NSMallocBlock:保存在堆中的 block,當(dāng)引用計(jì)數(shù)為 0 時(shí)會(huì)被銷毀。

MRC 下的 Block

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /*------------MRC-----------------*/ typedef long (^MyBlock)(int, int); MyBlock block1 = ^ long (int a, int b) { return a + b; }; NSLog(@"block1 = %@", block1); // block1 = <__NSGlobalBlock__: 0x47d0> int base = 100; MyBlock block2 = ^ long (int a, int b) { return base + a + b; }; NSLog(@"block2 = %@", block2); // block2 = <__NSStackBlock__: 0xbfffddf8> MyBlock block3 = [[block2 copy] autorelease]; NSLog(@"block3 = %@", block3); // block3 = <__NSMallocBlock__: 0x902fda0>

block1沒有使用任何外部變量,因此存儲(chǔ)在 代碼區(qū),編譯器給其的類型為NSGlobalBlock

block2使用到了局部變量,在定義(注意是定義,不是運(yùn)行)block2時(shí),局部變量base當(dāng)前值被copy到棧上,作為常量供Block使用。編譯器給其類型為NSStackBlock

block3?經(jīng)過拷貝,局部變量 base 的值被 copy 到堆中,編譯器給其類型為NSMallocBlock?總結(jié)說來,block 的類型取決于內(nèi)部使用的變量在哪。

ARC 下的 Block

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /*------------ARC-----------------*/ typedef long (^MyBlock)(int, int); MyBlock block1 = ^ long (int a, int b) { return a + b; }; NSLog(@"block1 = %@", block1); // block1 = <__NSGlobalBlock__: 0x100001080> int base = 100; MyBlock block2 = ^ long (int a, int b) { return base + a + b; }; NSLog(@"block2 = %@", block2); // block2 = <__NSMallocBlock__: 0x100203cf0> __block int sum = 100; MyBlock block3 = ^ long (int a, int b) { return sum + a + b; }; NSLog(@"block3 = %@", block3); // block3 = <__NSMallocBlock__: 0x100207100>

因?yàn)?ARC 下,編譯器幫我們管理內(nèi)存,所以只要內(nèi)部調(diào)用了外部變量,編譯器都會(huì) copy 一份變量到heap 中,并增加引用計(jì)數(shù)。 所以block2和block3的類型都是NSMallocBlock。其余和 MRC 一樣。

Tops:

以下情況,block 會(huì)拷貝到堆:

  • 當(dāng) block 調(diào)用 copy 方法時(shí),如果 block 在棧上,會(huì)被拷貝到堆上;

  • 當(dāng) block 作為函數(shù)返回值返回時(shí),編譯器自動(dòng)將 block 作為 _Block_copy 函數(shù),效果等同于 block 直接調(diào)用 copy 方法;

  • 當(dāng) block 被賦值給?_strong id 類型的對(duì)象或 block 的成員變量時(shí),編譯器自動(dòng)將 block 作為Block_copy 函數(shù),效果等同于 block 直接調(diào)用 copy 方法;

  • 當(dāng) block 作為參數(shù)被傳入方法名帶有 usingBlock 的 Cocoa Framework 方法或 GCD 的 API 時(shí)。這些方法會(huì)在內(nèi)部對(duì)傳遞進(jìn)來的 block 調(diào)用 copy 或 _Block_copy 進(jìn)行拷貝;

?

Objective-C Blocks Quiz


Example A

1 2 3 4 5 6 void exampleA() { char a = 'A'; ^{ printf("%cn", a); }(); }
  • Always works

Explain

This always works. The stack for exampleA doesn’t go away until after the block has finished executing. So whether the block is allocated on the stack or the heap, it will be valid when it is executed.

函數(shù)exampleA不會(huì)消失,直到 block 運(yùn)行結(jié)束,所以不管 block 在堆中還是棧中,它都可以運(yùn)行。


Example B

1 2 3 4 5 6 7 8 9 10 11 12 13 void exampleB_addBlockToArray(NSMutableArray *array) { char b = 'B'; [array addObject:^{ printf("%cn", b); }]; } void exampleB() { NSMutableArray *array = [NSMutableArray array]; exampleB_addBlockToArray(array); void (^block)() = [array objectAtIndex:0]; block(); }
  • Only works in ARC

Explain

Without ARC, the block is an NSStackBlock allocated on the stack of exampleB_addBlockToArray. By the time it executes in exampleB, the the block is no longer valid, because that stack has been cleared.

With ARC, the block is properly allocated on the heap as an autoreleased NSMallocBlock to begin with.

在 MRC中,這里的block 存在棧中,所以在執(zhí)行exampleB函數(shù)的exampleB_addBlockToArray(array);之后,b 變量變得無(wú)效,所以[array objectAtIndex:0]不能成功。 在 ARC 中,這個(gè) block 存在堆中,當(dāng)運(yùn)行到[array objectAtIndex:0],block 還沒被釋放,所以可以運(yùn)行。


Example C

1 2 3 4 5 6 7 8 9 10 11 12 void exampleC_addBlockToArray(NSMutableArray *array) { [array addObject:^{ printf("Cn"); }]; } void exampleC() { NSMutableArray *array = [NSMutableArray array]; exampleC_addBlockToArray(array); void (^block)() = [array objectAtIndex:0]; block(); }
  • Always works

Explain

Since the block doesn’t capture any variables in its closure, it doesn’t need any state set up at runtime. it gets compiled as an NSGlobalBlock. It’s neither on the stack nor the heap, but part of the code segment, like any C function. This works both with and without ARC.

因?yàn)檫@里的 block 是全局的NSConcreteGlobalBlock,所以不管是 ARC 還是 MRC 都是可以用的。


Example D

1 2 3 4 5 6 7 8 9 10 11 12 typedef void (^dBlock)(); dBlock exampleD_getBlock() { char d = 'D'; return ^{ printf("%cn", d); }; } void exampleD() { exampleD_getBlock()(); }
  • Only works in ARC

Explain

This is similar to example B. Without ARC, the block would be created on the stack of exampleD_getBlock and then immediately become invalid when that function returns. However, in this case, the error is so obvious that the compiler will fail to compile, with the error error: returning block that lives on the local stack.

With ARC, the block is correctly placed on the heap as an autoreleased NSMallocBlock.

在 MRC 時(shí),類似于example B,block 會(huì)被創(chuàng)建在棧中,所以當(dāng)block 返回時(shí),馬上失效。在這種情況下,錯(cuò)誤是顯而易見的,編譯器無(wú)法編譯成功。返回一個(gè)錯(cuò)誤:returning block that lives on the local stack。 在 ARC 中,當(dāng)自動(dòng)釋放池銷毀,block 才失效


Example E

1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef void (^eBlock)(); eBlock exampleE_getBlock() { char e = 'E'; void (^block)() = ^{ printf("%cn", e); }; return block; } void exampleE() { eBlock block = exampleE_getBlock(); block(); }
  • Only works in ARC

Explain

This is just like example D, except that the compiler doesn’t recognize it as an error, so this code compiles and crashes. Even worse, this particular example happens to work fine if you disable optimizations. So watch out for this working while testing and failing in production.

With ARC, the block is correctly placed on the heap as an autoreleased NSMallocBlock.

這題類似于example D。在 MRC 會(huì)造成崩潰。


Block_copy & copy

[block copy] 和 Block_copy(block)不等效。block 的賦值不是簡(jiǎn)單的拷貝,所以要拷貝最好使用 Block_copy()這個(gè)宏。

?

?

一、根據(jù)需求提出問題

  • 請(qǐng)耐心把這篇文章看完,你對(duì) Block 會(huì)有更深刻的了解。
  • 這里直接用一個(gè)需求來探究循環(huán)引用的問題:如果我想在Block中延時(shí)來運(yùn)行某段代碼,這里就會(huì)出現(xiàn)一個(gè)問題,看這段代碼: - (void)viewDidLoad {[super viewDidLoad];MitPerson*person = [[MitPerson alloc]init];__weak MitPerson * weakPerson = person;person.mitBlock = ^{dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakPerson test]; }); }; person.mitBlock(); } 直接運(yùn)行這段代碼會(huì)發(fā)現(xiàn)[weakPerson test];并沒有執(zhí)行,打印一下會(huì)發(fā)現(xiàn),weakPerson 已經(jīng)是 Nil 了,這是由于當(dāng)我們的?viewDidLoad?方法運(yùn)行結(jié)束,由于是局部變量,無(wú)論是 MitPerson 和 weakPerson 都會(huì)被釋放掉,那么這個(gè)時(shí)候在 Block 中就無(wú)法拿到正真的 person 內(nèi)容了。
  • 按如下方法修改代碼: - (void)viewDidLoad {[super viewDidLoad];MitPerson*person = [[MitPerson alloc]init];__weak MitPerson * weakPerson = person;person.mitBlock = ^{__strong MitPerson * strongPerson = weakPerson; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [strongPerson test]; }); }; person.mitBlock(); } 這樣當(dāng)2秒過后,計(jì)時(shí)器依然能夠拿到想要的 person 對(duì)象。

二、深入探究原理

    • 這里將會(huì)對(duì)每行代碼逐步進(jìn)行說明 1、開辟一段控件存儲(chǔ) person 類對(duì)象內(nèi)容,創(chuàng)建 person 強(qiáng)指針。 MitPerson*person = [[MitPerson alloc]init]; 2、創(chuàng)建一個(gè)弱指針 weakPerson 指向person對(duì)象內(nèi)容 __weak MitPerson * weakPerson = person; person.mitBlock = ^{ 3、在 person 對(duì)象的 Block 內(nèi)部創(chuàng)建一個(gè)強(qiáng)指針來指向 person 對(duì)象,為了保證當(dāng)計(jì)時(shí)器執(zhí)行代碼的時(shí)候,person 對(duì)象沒有被系統(tǒng)銷毀所以我們必須在系統(tǒng)內(nèi)部進(jìn)行一次強(qiáng)引用,并用 GCD 計(jì)時(shí)器引用 strongPerson,為了保留 person 對(duì)象,在下面會(huì)對(duì)這里更加詳細(xì)的說明。__strong MitPerson * strongPerson = weakPerson;dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[strongPerson test];}); }; 4、執(zhí)行 Block 代碼person.mitBlock();
    • 下面將詳細(xì)分析一下下面這段代碼: person.mitBlock = ^{ __strong MitPerson * strongPerson = weakPerson;dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[strongPerson test];}); };
    • 首先需要明白一些關(guān)于 Block 的概念:
      • 1、默認(rèn)情況下,block 是放在棧里面的
      • 2、一旦blcok進(jìn)行了copy操作,block的內(nèi)存就會(huì)被放在堆里面
      • 3、堆立面的block(被copy過的block)有以下現(xiàn)象
        • 1>?block內(nèi)部如果通過外面聲明的強(qiáng)引用來使用,那么block內(nèi)部會(huì)自動(dòng)產(chǎn)生一個(gè)強(qiáng)引用指向所使用的對(duì)象。
        • 2>?block內(nèi)部如果通過外面聲明的弱引用來使用,那么block內(nèi)部會(huì)自動(dòng)產(chǎn)生一個(gè)弱引用指向所使用的對(duì)象。
    • 我們進(jìn)行這段代碼的目的:
      • 首先,我們需要在 Block 塊中調(diào)用,person 對(duì)象的方法,既然是在 Block 塊中我們就應(yīng)該使用弱指針來引用外部變量,以此來避免循環(huán)引用。但是又會(huì)出現(xiàn)問題,什么問題呢?就是當(dāng)我計(jì)時(shí)器要執(zhí)行方法的時(shí)候,發(fā)現(xiàn)對(duì)象已經(jīng)被釋放了。
      • 接下來就是為了避免 person 對(duì)象在計(jì)時(shí)器執(zhí)行的時(shí)候被釋放掉:那么為什么 person 對(duì)象會(huì)被釋放掉呢?因?yàn)闊o(wú)論我們的person強(qiáng)指針還是 weakPerson 弱指針都是局部變量,當(dāng)執(zhí)行完ViewDidLoad 的時(shí)候,指針會(huì)被銷毀。對(duì)象只有被強(qiáng)指針引用的時(shí)候才不會(huì)被銷毀,而我們?nèi)绻苯右猛獠康膹?qiáng)指針對(duì)象又會(huì)產(chǎn)生循環(huán)引用,這個(gè)時(shí)候我們就用了一個(gè)巧妙的代碼來完成這個(gè)需求。
      • 首先在 person.mitBlock 引用外部 weakPerson,并在內(nèi)部創(chuàng)建一個(gè)強(qiáng)指針去指向 person 對(duì)象,因?yàn)樵趦?nèi)部聲明變量,Block 是不會(huì)強(qiáng)引用這個(gè)對(duì)象的,這也就在避免的 person.mitBlock 循環(huán)引用風(fēng)險(xiǎn)的同時(shí),又創(chuàng)建出了一個(gè)強(qiáng)指針指向?qū)ο蟆?/li>
      • 之后再用 GCD 延時(shí)器 Block 來引用相對(duì)于它來說是外部的變量 strongPerson ,這時(shí)延時(shí)器 Block 會(huì)默認(rèn)創(chuàng)建出來一個(gè)強(qiáng)引用來引用 person 對(duì)象,當(dāng) person.mitBlock 作用域結(jié)束之后 strongPerson 會(huì)跟著被銷毀,內(nèi)存中就僅剩下了 延時(shí)器 Block 強(qiáng)引用著 person 對(duì)象,2秒之后觸發(fā) test 方法,GCD Block 內(nèi)部方法執(zhí)行完畢之后,延時(shí)器和對(duì)象都被銷毀,這樣就完美實(shí)現(xiàn)了我們的需求。
    • 最后再用一張圖來闡述各個(gè)指針、Block 與對(duì)象之間的關(guān)系
      黑色代表強(qiáng)引用,綠色代表弱引用
      • 總結(jié):person.mitBlock 中創(chuàng)建 strongPerson 是為了能夠使 GCD Block 保存 person 對(duì)象,創(chuàng)建 strongPerson 時(shí)候使用 weakPerson 是為了避免 mitBlock 直接引用外部強(qiáng)指針變量所造成的循環(huán)引用。

        Block循環(huán)引用.png
      • ?

        ?

總結(jié)

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

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