block的原理是怎樣的领炫?本質(zhì)是什么膛腐?
block本質(zhì)上是一個(gè)OC對(duì)象 他內(nèi)部也有isa指針
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象
__block的作用是什么?有什么使用注意點(diǎn)执解?
解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題
會(huì)把__block變量包裝成一個(gè)對(duì)象
block的屬性修飾詞為什么是copy寞肖?使用block有哪些使用注意?
block一旦沒(méi)有進(jìn)行copy操作 就不會(huì)在堆上
注意循環(huán)引用的問(wèn)題
block在修改NSMutableArray衰腌,需不需要添加__block新蟆?
不需要
__block是修改auto變量的值
NSMutableArray addobject是使用了這個(gè)指針
block本質(zhì)
block本質(zhì)上是一個(gè)OC對(duì)象 他內(nèi)部也有isa指針
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象
block的變量捕獲(capture)
auto 自動(dòng)變量 離開(kāi)作用域就銷(xiāo)毀
只要是局部變量 block要訪問(wèn)局部變量 就要捕獲
自動(dòng)變量只能傳值的原因是隨時(shí)可能會(huì)銷(xiāo)毀 那塊地址就沒(méi)了 如果再傳地址進(jìn)去 就會(huì)訪問(wèn)到壞內(nèi)存 static變量是因?yàn)槟菈K內(nèi)存存在 可以通過(guò)地址來(lái)進(jìn)行訪問(wèn)
局部變量需要捕獲的原因是因?yàn)橐绾瘮?shù)訪問(wèn) 全局變量是任何函數(shù)都可以直接使用,所以不需要進(jìn)行捕獲
block的類(lèi)型
block有3種類(lèi)型,可以通過(guò)調(diào)用class方法或者isa指針查看具體類(lèi)型右蕊,最終都是繼承自NSBlock類(lèi)型
__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__ ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )
一切以運(yùn)行時(shí)的結(jié)果為準(zhǔn) 使用Clang轉(zhuǎn)成的C++代碼不一定完全一致 只能作為參考
在棧block里面 函數(shù)調(diào)用完畢 里面的數(shù)據(jù)可能是垃圾數(shù)據(jù)
在ARC環(huán)境下憎妙,編譯器會(huì)根據(jù)情況自動(dòng)將棧上的block復(fù)制到堆上
1.block作為函數(shù)返回值的時(shí)候
2.將block賦值給強(qiáng)指針(__strong)的時(shí)候
3.block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
4.block作為GCD API的方法參數(shù)時(shí)
椩俨祝空間的block是無(wú)法對(duì)外面的變量進(jìn)行持有的 也就是強(qiáng)引用的 堆空間的block會(huì)對(duì)外面的變量進(jìn)行強(qiáng)引用的 保住他的生命(當(dāng)block銷(xiāo)毀的時(shí)候 也會(huì)對(duì)變量進(jìn)行release)
如果代碼里面使用了__weak 在使用clang轉(zhuǎn)換OC為C++代碼時(shí)宾濒,可能會(huì)遇到cannot create __weak reference in file using manual reference 那么需要指定運(yùn)行時(shí)版本 需要arc
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
對(duì)象類(lèi)型的auto變量
當(dāng)block內(nèi)部訪問(wèn)了對(duì)象類(lèi)型的auto變量時(shí)
1.如果block是在棧上 都不會(huì)對(duì)auto變量產(chǎn)生強(qiáng)引用
2.如果block被拷貝到堆上
@.會(huì)調(diào)用block內(nèi)部的copy函數(shù)
@.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)或者弱引用
3.如果block從堆上移除
@.會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
@.dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
@._Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的auto變量 類(lèi)似于release
解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題
1.使用static修飾 會(huì)把變量地址捕獲到block里面
2.使用全局變量來(lái) 不會(huì)捕獲到block里面 直接就可以修改
3.使用__block修飾
不使用static變量和全局變量的原因是 不想創(chuàng)建一個(gè)變量永遠(yuǎn)占據(jù)這塊內(nèi)存
__block不能修飾全局變量嘀掸、靜態(tài)變量(static)
編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象
__block修飾auto變量的內(nèi)存管理
__block修飾變量的時(shí)候
1.當(dāng)block在棧上時(shí) 并不會(huì)對(duì)__block變量產(chǎn)生強(qiáng)引用
2.當(dāng)block被copy到堆時(shí)
a.會(huì)調(diào)用block內(nèi)部的copy函數(shù)
b.copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
c. _Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(retain)
block銷(xiāo)毀的時(shí)候
當(dāng)block從堆中移除時(shí)
- 會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
- _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的__block變量(release)
對(duì)象類(lèi)型的auto變量、__block修飾的auto變量的內(nèi)存管理總結(jié)
1.當(dāng)block在棧上的時(shí)候 都不會(huì)產(chǎn)生強(qiáng)引用
2.當(dāng)block拷貝到堆上時(shí) 通過(guò)copy函數(shù)處理他們
a. __block變量(假設(shè)變量名叫做a)
_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
b.對(duì)象類(lèi)型的auto變量(假設(shè)變量名叫做p)
_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
3.當(dāng)block從堆上移除時(shí)规惰,都會(huì)通過(guò)dispose函數(shù)來(lái)釋放它們
a.__block變量(假設(shè)變量名叫做a)
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
b.對(duì)象類(lèi)型的auto變量(假設(shè)變量名叫做p)
_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
__block的__forwarding指針
保證不管訪問(wèn)的是棧中的block還是堆中的block 只要通過(guò)__forwarding指針都可以訪問(wèn)到堆中的block
__block修飾對(duì)象類(lèi)型的內(nèi)存管理
當(dāng)block拷貝到堆上 會(huì)把__block修飾的對(duì)象這個(gè)整體的結(jié)構(gòu)體拷貝到堆上 同時(shí),會(huì)調(diào)用這個(gè)結(jié)構(gòu)體內(nèi)部的copy函數(shù)
1.當(dāng)__block變量在棧上時(shí)睬塌,不會(huì)對(duì)指向的對(duì)象產(chǎn)生強(qiáng)引用
2.當(dāng)__block變量被copy到堆時(shí)
a.會(huì)調(diào)用__block變量?jī)?nèi)部的copy函數(shù)
b.copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
c._Block_object_assign函數(shù)會(huì)根據(jù)所指向?qū)ο蟮男揎椃╛_strong、__weak歇万、__unsafe_unretained)做出相應(yīng)
的操作揩晴,形成強(qiáng)引用(retain)或者弱引用(注意:這里僅限于ARC時(shí)會(huì)retain,MRC時(shí)不會(huì)retain)
3.如果__block變量從堆上移除
a.會(huì)調(diào)用__block變量?jī)?nèi)部的dispose函數(shù)
b.dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
c._Block_object_dispose函數(shù)會(huì)自動(dòng)釋放指向的對(duì)象(release)
這里僅限于ARC時(shí)會(huì)retain堕花,MRC時(shí)不會(huì)retain
解決循環(huán)引用問(wèn)題 -ARC
用__weak文狱、__unsafe_unretained解決
weak 不會(huì)產(chǎn)生強(qiáng)引用 指向的對(duì)象銷(xiāo)毀時(shí) 會(huì)自動(dòng)讓指針置為nil
__unsafe_unretained 不會(huì)產(chǎn)生強(qiáng)引用 不安全 指向的對(duì)象銷(xiāo)毀時(shí) 指針存儲(chǔ)的地址值不變
可以使用__block來(lái)解決循環(huán)引用問(wèn)題 但是 必須要執(zhí)行block 和把對(duì)象置為nil 如果沒(méi)有執(zhí)行block 那么就會(huì)存在循環(huán)引用
__block id weakSelf = self;
self.block = ^{
printf( "%p", weakSelf);
weakSelf = nil ;
};
self.block() ;
解決循環(huán)引用問(wèn)題 -MRC
在MRC下不支持__weak
用__block、__unsafe_unretained解決
由于在MRC下 使用__block修飾變量 不會(huì)對(duì)變量產(chǎn)生強(qiáng)引用 這樣就可以使用__block來(lái)解決循環(huán)引用問(wèn)題