block的類(lèi)型
block有3種類(lèi)型,可以通過(guò)調(diào)用class方法或者isa指針查看具體類(lèi)型辰妙,最終都是繼承自NSBlock類(lèi)型
- __NSGlobalBlock__ (_NSConcreteGlobalBlock )
- __NSStackBlock__ (_NSConcreteStackBlock )
- __NSMallocBlock__ (_NSConcreteMallocBlock )
應(yīng)用程序內(nèi)存分配 |
---|
程序區(qū)域 .text區(qū) |
數(shù)據(jù)區(qū)域 .data區(qū) |
堆區(qū) |
棧區(qū) |
不同類(lèi)型block的存放區(qū)域
生成不同類(lèi)型的block
block類(lèi)型 | 環(huán)境 |
---|---|
NSGlobalBlock(數(shù)據(jù)區(qū)) | 沒(méi)有訪問(wèn)auto變量 |
NSStackBlock(棧區(qū)) | 訪問(wèn)了auto變量 |
NSMallocBlock(堆區(qū)) | NSStackBlock調(diào)用了copy |
每一種類(lèi)型的block調(diào)用copy后的結(jié)果如下所示:
block類(lèi)型 | 副本源的配置存儲(chǔ)域 | 復(fù)制效果 |
---|---|---|
NSGlobalBlock(數(shù)據(jù)區(qū)) | 棧區(qū) | 從棧復(fù)制到堆區(qū) |
NSStackBlock(棧區(qū)) | 程序的數(shù)據(jù)區(qū) | 什么也不做 |
NSMallocBlock(堆區(qū)) | 堆區(qū) | 引用計(jì)數(shù)增加 |
block的copy
在ARC環(huán)境下压状,編譯器會(huì)根據(jù)情況自動(dòng)將棧上的block復(fù)制到堆上仆抵,比如以下情況
- block作為函數(shù)返回值時(shí)
- 將block賦值給__strong指針時(shí)
- block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
- block作為GCD API的方法參數(shù)時(shí)
MRC下block屬性的建議寫(xiě)法
@property (copy, nonatomic) void (^block)(void);`
ARC下block屬性的建議寫(xiě)法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
對(duì)象類(lèi)型的auto變量
當(dāng)block內(nèi)部訪問(wèn)了對(duì)象類(lèi)型的auto變量時(shí)
如果block是在棧上,將不會(huì)對(duì)auto變量產(chǎn)生強(qiáng)引用
如果block被拷貝到堆上
- 如果block被拷貝到堆上
- copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
- _Block_object_assign函數(shù)會(huì)根據(jù)auto變量的修飾符(__strong种冬、__weak镣丑、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用
函數(shù) | 點(diǎn)用時(shí)機(jī) |
---|---|
__main_block_copy_0 | 棧上的block復(fù)制到堆時(shí) |
__main_block_dispose_0 | 堆上的block被廢棄時(shí) |
//block被拷貝到堆上時(shí)調(diào)用
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
//會(huì)根據(jù)auto變量的修飾符(__strong碌廓、__weak、__unsafe_unretained)做出相應(yīng)的操作剩盒,形成強(qiáng)引用(retain)或者弱引用
_Block_object_assign((void*)&dst->obj,
(void*)src->obj,
8/*BLOCK_FIELD_IS_BYREF*/);
}
//block從堆上移除時(shí)調(diào)用
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
//會(huì)自動(dòng)釋放引用的auto變量(release)
_Block_object_dispose((void*)src->obj,
8/*BLOCK_FIELD_IS_BYREF*/);
}
__weak修飾符
__weak修飾符可以是block生成的結(jié)構(gòu)體中捕獲的變量為_(kāi)_weak變量..則可以對(duì)變量進(jìn)行弱引用谷婆,解決循環(huán)引用問(wèn)題
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
//捕獲__weak變量
NSString __weak *name;
.
.
.
};
在使用clang轉(zhuǎn)換OC為C++代碼時(shí),可能會(huì)遇到以下問(wèn)題
cannot create __weak reference in file using manual reference
解決方案:支持ARC辽聊、指定運(yùn)行時(shí)系統(tǒng)版本纪挎,比如
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
__block修飾符
__block
可以用于解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題.但是__block
不能修飾全局變量、靜態(tài)變量(static)
編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象
__block int age = 13;
^{
NSLog(@"%d", age);
}();
會(huì)生成一下C++代碼:
struct __main_block_impl_1 {
struct __block_impl impl;
struct __main_block_desc_1* Desc;
__Block_byref_age_2 *age; // by ref
__main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, __Block_byref_age_2 *_age, int flags=0) : age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_age_2 {
void *__isa;
__Block_byref_age_2 *__forwarding;
int __flags;
int __size;
int age;
};