引導(dǎo)語:
- Block原理是怎樣的?本質(zhì)是什么?
- _block的作用是什么?使用需要注意什么?
- block的屬性修飾詞為什么是copy?使用block有哪些使用注意?
- block在修改NSMutableArray時(shí)需不需要添加_block?
我們通常代碼中使用的block是什么:為什么能夠保存一段代碼,而控制block內(nèi)部代碼塊執(zhí)行時(shí)機(jī)呢?
Q:Block本質(zhì)是什么?
block是封裝了函數(shù)調(diào)用、以及函數(shù)調(diào)用環(huán)境的OC對象。
函數(shù)調(diào)用:block 的{}代碼塊。
函數(shù)調(diào)用環(huán)境:block傳入的參數(shù)、捕獲的auto變量。
相關(guān)圖:

查看block源碼:
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// 構(gòu)造函數(shù)(類似于OC的init方法),返回結(jié)構(gòu)體對象
__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;
}
};
// 封裝了block執(zhí)行邏輯的函數(shù)
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_c60393_mi_0);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
// 定義block變量
void (*block)(void) = &__main_block_impl_0(
__main_block_func_0,
&__main_block_desc_0_DATA
);
// 執(zhí)行block內(nèi)部的代碼
block->FuncPtr(block);
}
return 0;
}

- FuncPtr:指向調(diào)用函數(shù)的地址
- __main_block_desc_0 :block描述信息
- Block_size:block的大小
C語言中不允許結(jié)構(gòu)體內(nèi)有方法函數(shù)
C++允許結(jié)構(gòu)體內(nèi)些方法函數(shù)(構(gòu)造函數(shù)),構(gòu)造函數(shù)類似OC中的init
第二部分:Block捕獲變量
Q:下述代碼輸出值為多少?
int age=10;
void (^Block)(void) = ^{
NSLog(@"age:%d",age);
};
age = 20;
Block();
輸出值為 age:10
原因:創(chuàng)建block的時(shí)候,已經(jīng)把a(bǔ)ge的值存儲在里面了。
Q:下列代碼輸出值分別為多少?
auto int age = 10;
static int num = 25;
void (^Block)(void) = ^{
NSLog(@"age:%d,num:%d",age,num);
};
age = 20;
num = 11;
Block();
輸出結(jié)果為:age:10,num:11
原因:auto變量block訪問方式是值傳遞,static變量block訪問方式是指針傳遞
源碼證明:
int age = __cself->age; // bound by copy
int *num = __cself->num; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age, (*num));
int age = 10;
static int num = 25;
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &num));
age = 20;
num = 11;
上述代碼可查看 static修飾的變量,是根據(jù)指針訪問的
Q:為什么block對auto和static變量捕獲有差異?
auto:自動(dòng)變量,離開作用域銷毀,不采用指針訪問;
static:變量一直保存在內(nèi)存中,可以訪問內(nèi)存,指針訪問即可。
Q:block對全局變量的捕獲方式是?
block不需要對全局變量捕獲,都是直接采用取值的
Q:為什么局部變量需要捕獲?
考慮作用域的問題,需要跨函數(shù)訪問,就需要捕獲
Q:block的變量捕獲(capture)
為了保證block內(nèi)部能夠正常訪問外部的變量,block有個(gè)變量捕獲機(jī)制

Q:block內(nèi)訪問self是否會捕獲(capture)
會,self是當(dāng)調(diào)用block函數(shù)的參數(shù),參數(shù)是局部變量,self指向調(diào)用者
Q:block里訪問成員變量是否會捕獲?
會,成員變量_xxx的訪問其實(shí)是self->xxx,先捕獲self,再通過self訪問里面的成員變量.
第三部分 Block類型
Q:block有哪幾種類型?
block的類型,取決于isa指針,可以通過調(diào)用class方法或者isa指針查看具體類型,最終都是繼承自NSBlock類型
- __NSGlobalBlock __ ( _NSConcreteGlobalBlock )
- __NSStackBlock __ ( _NSConcreteStackBlock )
- __NSMallocBlock __ ( _NSConcreteMallocBlock )
代碼示例:
void (^block1)(void) = ^{
NSLog(@"block1");
};
NSLog(@"%@",[block1 class]);
NSLog(@"%@",[[block1 class] superclass]);
NSLog(@"%@",[[[block1 class] superclass] superclass]);
NSLog(@"%@",[[[[block1 class] superclass] superclass] superclass]);
NSLog(@"%@",[[[[[block1 class] superclass] superclass] superclass] superclass]);
輸出結(jié)果:
NSGlobalBlock
__NSGlobalBlock
NSBlock
NSObject
null
上述代碼輸出了block1的類型,也證實(shí)了block是對象,最終繼承NSObject.
如果我們在lldb的過程中觀看block的類型時(shí),發(fā)現(xiàn)編譯階段block都是stack形式,但是打印出來會顯示不同類型。這是因?yàn)镺C位動(dòng)態(tài)語言,在這個(gè)過程中會對其進(jìn)行處理。所以一切以runtime運(yùn)行時(shí)的結(jié)果為準(zhǔn)。
Q:各類型的block在內(nèi)存中如何分配的?
- __NSGlobalBlock __ 在數(shù)據(jù)區(qū)
- __NSMallocBlock __ 在堆區(qū)
- __NSStackBlock __ 在棧區(qū)
堆:動(dòng)態(tài)分配內(nèi)存,需要程序員自己申請,程序員自己管理
棧:自動(dòng)分配內(nèi)存,自動(dòng)銷毀,先入后出,棧上的內(nèi)容存在自動(dòng)銷毀的情況
編譯階段:此階段會把代碼 編入代碼區(qū)、data區(qū)內(nèi)

Q:如何判斷block是哪種類型?
| Block類型 | 環(huán)境 |
|---|---|
| _NSGlobalBlock | 沒有訪問auto變量 |
| _NSStackBlock | 訪問了auto變量 |
| _NSMallocBlock | _NSStackBlock 調(diào)用了copy |
Q:對每種類型block調(diào)用copy操作后是什么結(jié)果?
| Block類型 | 原配置存儲 | 復(fù)制效果 |
|---|---|---|
| _NSGlobalBlock | 數(shù)據(jù)區(qū) | 什么也不會做 |
| _NSStackBlock | 棧區(qū) | 從棧復(fù)制到堆上 |
| _NSMallocBlock | 堆區(qū) | 引用計(jì)數(shù)增加 |
總結(jié):棧上block用完,其內(nèi)部的數(shù)據(jù)變成垃圾數(shù)據(jù),說不準(zhǔn)是啥。所以copy棧數(shù)據(jù)到堆上使用才可以。
Q:在ARC環(huán)境下,編譯器什么情況下會自動(dòng)將棧上的block復(fù)制到堆上?
- block作為函數(shù)返回值時(shí)
- 將block賦值給__strong指針時(shí)
- block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
- block作為GCD API的方法參數(shù)時(shí)
ARC下block屬性的建議寫法
@property (copy, nonatomic) void (^block)(void);
MRC下block屬性的建議寫法
@property (copy, nonatomic) void (^block)(void);
第四部分:對象類型的auto變量
Q:ARC下述代碼中Person對象是否會釋放?
示例代碼:
typedef void(^XBTBlock)(void);
XBTBlock block;
{
Person *p = [[Person alloc] init];
p.age = 10;
block = ^{
NSLog(@"======= %d",p.age);
};
}
Person.m
- (void)dealloc{
NSLog(@"Person - dealloc");
}
輸出結(jié)果:不會打印Person - dealloc
轉(zhuǎn)化C++代碼后:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *person;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, MJPerson *__strong _person, int flags=0) : person(_person) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
上述結(jié)果:
block為堆block,block里面有一個(gè)Person指針,Person指針指向Person對象。只要block還在,Person就還在。block強(qiáng)引用了Person對象。
疑問:此處的isa指針明明指向生成的stackBlock呀,為什么最后還是強(qiáng)引用person對象呢?是不是什么地方有錯(cuò)誤?
推論:此情況只是編譯時(shí)候產(chǎn)生的,我們在runtime的時(shí)候?qū)@個(gè)類型進(jìn)行了改變,我們通過打印class 進(jìn)行block類型查看即可。所以可以引導(dǎo)出以下結(jié)論。
結(jié)論: 在ARC情況下會自動(dòng)將stackBlock拷貝到堆上生成mallocBlock,從而強(qiáng)引用里面person對象
Q:上述代碼改換成MRC,Person對象會釋放么?
會的!
堆空間的block會對Person對象retain操作,擁有一次Person對象。
Q:下列代碼中Person是否會被釋放?
@autoreleasepool {
XBTBlock block;
{
Person *p = [[Person alloc] init];
p.age = 10;
__weak Person *weakPersn = p;
block = ^{
NSLog(@"======= %d",weakPersn.age);
};
}
NSLog(@"--------------");
}
答案:會釋放
原因: __weak修飾對象后,我們block捕獲的就是一個(gè)弱引用的對象,所以block不會強(qiáng)引用person對象,在person出了作用域后就可以釋放了。
小結(jié)
無論MRC還是ARC,棧空間上的block,不會持有對象;堆空間的block,會持有對象。
Q:當(dāng)block內(nèi)部訪問了對象類型的auto變量時(shí),是否會強(qiáng)引用?
答案:分情況討論,分為棧block和堆block
棧block: 如果block是在棧上,將不會對auto變量產(chǎn)生強(qiáng)引用(棧上的block隨時(shí)會被銷毀,自身都難保,也沒必要去強(qiáng)引用其他對象)
堆block:
1.如果block被拷貝到堆上:
a) 會調(diào)用block內(nèi)部的copy函數(shù)
b) copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
c) _Block_object_assign函數(shù)會根據(jù)auto變量的修飾符(__strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用
2.如果block從堆上移除
a) 會調(diào)用block內(nèi)部的dispose函數(shù)
b) dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
c) _Block_object_dispose函數(shù)會自動(dòng)釋放引用的auto變量(release)
正確答案:
- 如果block在??臻g,不管外部變量是強(qiáng)引用還是弱引用,block都會弱引用訪問對象
- 如果block在堆空間,如果外部強(qiáng)引用,block內(nèi)部也是強(qiáng)引用;如果外部弱引用,block內(nèi)部也是弱引用
Q1:gcd的block中引用 Person對象什么時(shí)候銷毀?
代碼:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
Person *person = [[Person alloc] init];
person.age = 10;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"age:%d",person.age);
});
NSLog(@"touchesBegan");
}
輸出結(jié)果:
14:36:03.395120+0800 test[1032:330314] touchesBegan
14:36:05.395237+0800 test[1032:330314] age:10
14:36:05.395487+0800 test[1032:330314] Person-dealloc
原因:gcd的block默認(rèn)會做copy操作,即dispatch_after的block是堆block,block會對Person強(qiáng)引用,block銷毀時(shí)候Person才會被釋放。
Q2:上述代碼如果換成__weak,Person什么時(shí)候釋放?
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
Person *person = [[Person alloc] init];
person.age = 10;
__weak Person *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"age:%p",weakPerson);
});
NSLog(@"touchesBegan");
}
輸出結(jié)果:
14:38:42.996990+0800 test[1104:347260] touchesBegan
14:38:42.997481+0800 test[1104:347260] Person-dealloc
14:38:44.997136+0800 test[1104:347260] age:0x0
原因:使用__weak修飾過后的對象,堆block會采用弱引用,無法延時(shí)Person的壽命,所以在touchesBegan函數(shù)結(jié)束后,Person就會被釋放,gcd就無法捕捉到Person。
Q3:如果gcd內(nèi)包含gcd,Person會什么時(shí)候釋放?
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
Person *person = [[Person alloc] init];
person.age = 10;
__weak Person *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"2-----age:%p",person);
});
NSLog(@"1-----age:%p",weakPerson);
});
NSLog(@"touchesBegan");
}
輸出結(jié)果:
14:48:01.293818+0800 test[1199:403589] touchesBegan
14:48:05.294127+0800 test[1199:403589] 1-----age:0x604000015eb0
14:48:08.582807+0800 test[1199:403589] 2-----age:0x604000015eb0
14:48:08.583129+0800 test[1199:403589] Person-dealloc
原因:gcd內(nèi)部只要有強(qiáng)引用Person,Person就會等待執(zhí)行完再銷毀!所以Person銷毀時(shí)間為7秒。
Q4:如果gcd內(nèi)部先強(qiáng)引用后弱引用,Person什么時(shí)候釋放?
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
Person *person = [[Person alloc] init];
person.age = 10;
__weak Person *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"2-----age:%p",weakPerson);
});
NSLog(@"1-----age:%p",person);
});
NSLog(@"touchesBegan");
}
輸出結(jié)果
14:52:29.036878+0800 test[1249:431302] touchesBegan
14:52:33.417862+0800 test[1249:431302] 1-----age:0x6000000178d0
14:52:33.418178+0800 test[1249:431302] Person-dealloc
14:52:36.418204+0800 test[1249:431302] 2-----age:0x0
原因:Person會等待強(qiáng)引用執(zhí)行完畢后釋放,只要強(qiáng)引用執(zhí)行完,就不會等待后執(zhí)行的弱引用,會直接釋放的,所以Person釋放時(shí)間為4秒。_weak修飾person后,則block不會強(qiáng)引用它,所以出了其作用域就會被銷毀。
第五部分:__block修飾符
Q:block能否修改變量值?
auto修飾變量:block無法修改,因?yàn)閎lock使用的時(shí)候是內(nèi)部創(chuàng)建了變量來保存外部的變量的值,block只有修改內(nèi)部自己變量的權(quán)限,無法修改外部變量的權(quán)限。
static修飾變量:block可以修改,因?yàn)閎lock把外部static修飾變量的指針存入,block直接修改指針指向變量值,即可修改外部變量值。
全局變量值:全局變量無論哪里都可以修改,當(dāng)然block內(nèi)部也可以修改。
Q:__block int age = 10,系統(tǒng)做了哪些?
答案:編譯器會將__block變量包裝成一個(gè)對象
查看c++源碼:
struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding;//age的地址
int __flags;
int __size;
int age;//age 的值
};
Q:__block 修飾符作用?
- _block可以用于解決block內(nèi)部無法修改auto變量值的問題
- __block不能修飾全局變量、靜態(tài)變量(static)
- 編譯器會將__block變量包裝成一個(gè)對象
- __block修改變量:
age->__forwarding->age -
__Block_byref_age_0結(jié)構(gòu)體內(nèi)部地址和外部變量age是同一地址
__block的forwarding指針指向.png
Q:__block 能修改auto變量的本質(zhì)?
- 編譯器會將__block變量包裝成一個(gè)對象(在內(nèi)存單獨(dú)有空間保存數(shù)據(jù))
- __block修改變量:
age->__forwarding->age
說明:block內(nèi)部訪問的&age地址是__block對象結(jié)構(gòu)體內(nèi)部的age地址。
Q:block在修改NSMutableArray,需不需要添加__block?
不需要。block內(nèi)部可以拿到數(shù)組的&p地址,通過指針對數(shù)組進(jìn)行加減等操作是可以的。
Q:block可以向NSMutableArray添加元素么?
NSMutableArray *arr = [NSMutableArray array];
Block block = ^{
[arr addObject:@"123"];
[arr addObject:@"2345"];
};
答案:可以,因?yàn)槭莂ddObject是使用NSMutableArray變量,而不是通過指針改變NSMutableArray。但是如果是arr = nil,這就是改變了NSMutableArray變量,會報(bào)錯(cuò),這時(shí)需要用__block修飾才行。
5.1 __block的內(nèi)存管理
當(dāng)block在棧上時(shí),并不會對__block變量產(chǎn)生強(qiáng)引用。
block用到某個(gè)對象時(shí)候,會對這個(gè)對象進(jìn)行內(nèi)存管理。
Q:block的屬性修飾詞為什么是copy?
block一旦沒有進(jìn)行copy操作,就不會在堆上
block在堆上,程序員就可以對block做內(nèi)存管理等操作,可以控制block的生命周期。在棧上出來作用域數(shù)據(jù)可能變成臟數(shù)據(jù)

Q:當(dāng)block被copy到堆時(shí),對__block修飾的變量做了什么?
- 會調(diào)用block內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
- _Block_object_assign函數(shù)會對__block變量形成強(qiáng)引用(retain)
-
對于__block 修飾的變量 assign函數(shù)對其強(qiáng)引用;對于外部對象 assign函數(shù)根據(jù)外部如何引用而引用
block0復(fù)制到堆上.png

Q:當(dāng)block從堆中移除時(shí),對__block修飾的變量做了什么?
- 會調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
-
_Block_object_dispose函數(shù)會自動(dòng)釋放引用的__block變量(release)
block被廢棄.png

Q:block對象類型的auto變量、__block變量的區(qū)別?
從幾方面回答:
1.當(dāng)block在棧上時(shí),對它們都不會產(chǎn)生強(qiáng)引用
2.當(dāng)block拷貝到堆上時(shí)
- 都會通過copy函數(shù)來處理它們
- 對于__block 修飾的變量 assign函數(shù)對其強(qiáng)引用;對于外部對象 assign函數(shù)根據(jù)外部如何引用而引用。注意第三個(gè)參數(shù)值是不一樣的
__block變量(假設(shè)變量名叫做a)
_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
對象類型的auto變量(假設(shè)變量名叫做p)
_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
3.當(dāng)block從堆上移除時(shí)
- 都會通過dispose函數(shù)來釋放它們
__block變量(假設(shè)變量名叫做a)
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
對象類型的auto變量(假設(shè)變量名叫做p)
_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
4.__block的__forwarding指針
- 棧上__block的__forwarding指向本身
-
棧上__block復(fù)制到堆上后,棧上block的__forwarding指向堆上的block,堆上block的__forwarding指向本身
forwarding指向.png
Q:被__block修飾的對象類型在block上如何操作的?
分幾方面回答:
1.當(dāng)__block變量在棧上時(shí),不會對指向的對象產(chǎn)生強(qiáng)引用
2.當(dāng)__block變量被copy到堆時(shí)
- 會調(diào)用__block變量內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
- _Block_object_assign函數(shù)會根據(jù)所指向?qū)ο蟮男揎椃╛_strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用(注意:
這里僅限于ARC時(shí)會retain,MRC時(shí)不會retain) - MRC環(huán)境下不會根據(jù)對象的修飾符引用,都是弱引用(注意是在有__block修飾的前提下)
3.如果__block變量從堆上移除
- 會調(diào)用__block變量內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
- _Block_object_dispose函數(shù)會自動(dòng)釋放指向的對象(release)
__block修飾對象、auto修飾對象內(nèi)存指向圖有什么區(qū)別?
auto修飾:block內(nèi)的person指針,指向的MJPerson類對象內(nèi)存。
__block修飾:block內(nèi)的strongPerson指針,指向__block類對象 結(jié)構(gòu)體struct_block_byref_person。struct_block_byref_person內(nèi)的weakPerson根據(jù)屬性強(qiáng)弱指向MJPerson的類對象。


第六部分 block循環(huán)引用
block中如何形成的循環(huán)?
1.block強(qiáng)持有對象person,對象person強(qiáng)持有block。
2.block強(qiáng)持有__block對象,__block強(qiáng)持有person,person強(qiáng)持有block



Q:ARC下如何解決block循環(huán)引用的問題?
三種方式:__weak、__unsafe_unretained、__block
1.第一種方式:__weak
Person *person = [[Person alloc] init];
// __weak Person *weakPerson = person;
__weak typeof(person) weakPerson = person;
person.block = ^{
NSLog(@"age is %d", weakPerson.age);
};
2.第二種方式:__unsafe_unretained
__unsafe_unretained Person *person = [[Person alloc] init];
person.block = ^{
NSLog(@"age is %d", weakPerson.age);
};
3.第三種方式:__block
__block Person *person = [[Person alloc] init];
person.block = ^{
NSLog(@"age is %d", person.age);
person = nil;
};
person.block();
4.三種方法比較
-
__weak:不會產(chǎn)生強(qiáng)引用,指向的對象銷毀時(shí),會自動(dòng)讓指針置為nil。 -
__unsafe_unretained:不會產(chǎn)生強(qiáng)引用,不安全,指向的對象銷毀時(shí),指針存儲的地址值不變。 -
__block:必須把引用對象置位nil,并且要調(diào)用該block();
Q:MRC下如何解決block循環(huán)引用的問題?
MRC環(huán)境下不支持弱指針,也就是不支持__weak。
所以兩種方式:__unsafe_unretained、__block
1.第一種方式:__unsafe_unretained
__unsafe_unretained Person *person = [[Person alloc] init];
person.block = ^{
NSLog(@"age is %d", weakPerson.age);
};
2.第二種方式:__block
__block Person *person = [[Person alloc] init];
person.block = ^{
NSLog(@"age is %d", person.age);
};
說明:本文參照李明杰老師課程、《iOS-Block本質(zhì)》



