圖片.png
寫在最前面
在平時工作中,控制器和控制器之間的反向傳值得時候我們通常會使用block,代理和通知,今天我們來講講block。在我們使用block的時候就會注意到一點,我們創建的時候為什么使用copy類型呢?
解析block
block:可以理解為匿名的函數,就是預先準備好的一段代碼,在需要的時候調用。
其中主要記錄一下這幾個主要的block參數即可
- __block_impl:這是一個結構體,也是C面向對象的體現,可以理解為block的基類;
- __main_block_impl_0: 可以理解為block變量;
- __main_block_func_0: 可以理解為匿名函數;
- __main_block_desc_0:block的描述, Block_size;
1、__block_impl
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
2、__main_block_impl_0
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;
}
};
3、__main_block_func_0
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gc_5fkhcz0n6px48vzc744hmp6c0000gn_T_main_eef954_mi_0);
}
4、 __main_block_desc_0
staticstruct __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;
void (*myblock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)myblock)->FuncPtr)((__block_impl *)myblock);
}
return 0;
}
注意事項:block容易造成循環引用,在block里面如果使用了self,然后形成強引用時,需要打斷循環引用;在MRC下用_block,在ARC下使用__weak;
關于block在內存中的位置
block快的存儲位置(block入口的地址)可能存放在3個地方:代碼區(全局區)、堆區、棧區(ARC情況下回自動拷貝到堆區、因此ARC下只有兩個地方:代碼區和堆區)。
- 代碼區:不訪問出去棧區的變量(如局部變量),且不訪問堆區的變量(如用alloc創建的對象)時,此時block存放在代碼區;
- 堆區:如果訪問了處于堆區的變量(如局部變量),或堆區的變量(如用alloc創建的對象),此時block存方在堆區;--需要注意
-1 實際是放在棧區,在ARC情況下油自動拷貝到堆區,如果不是ARC則存放在棧區,所在函數執行完畢就回釋放,想再外面調用需要用copy指向它,這樣就拷貝到了堆區,strong屬性不會拷貝、會造成野指針錯區。(需要理解ARC是一種編譯器特性,即編譯器在編譯時在核實的地方插入retain、release、autorelease,而不是iOS的運行時特性)。
-2 此外代碼存在堆區時,需要注意,因為堆區不像代碼區不變化,堆區是動態的(不斷的創建銷毀),當沒有強指針指向的時候就會被銷毀,如果再去訪問這段代碼時,程序就會崩潰!所以此種情況在定義block屬性時需要指定為strong or copy。block是一段代碼,即不可變,所以使用copy也不會深拷貝。
總結
根據上面提到的block存放位置可知,當使用strong類型的有可能造成野指針問題,而copy的時候是沒有問題的。