幾個(gè)概念點(diǎn)分析的比較好的文章
- 黑幕背后的Autorelease
- Runloop
- runtime
- SDWebImage實(shí)現(xiàn)分析
- 內(nèi)存惡鬼drawRect
- 找不到好用的三方庫?看這里
- 續(xù)更中...
整理的部分iOS 面試題
什么時(shí)候在 block 中不需要使用 weakSelf?
問題:我們知道,在使用 block 的時(shí)候,為了避免產(chǎn)生循環(huán)引用,通常需要使用 weakSelf 與 strongSelf,寫下面這樣的代碼:
__weak typeof(self) weakSelf = self;
[self doSomeBlockJob:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
...
}
}];
那么請問:什么時(shí)候在 block里面用self,不需要使用weakself?
當(dāng)block本身不被self 持有,而被別的對象持有,同時(shí)不產(chǎn)生循環(huán)引用的時(shí)候,就不需要使用weakself了。最常見的代碼就是UIView的動(dòng)畫代碼,我們在使用UIView animateWithDuration:animations方法 做動(dòng)畫的時(shí)候,并不需要使用weakself,因?yàn)橐贸钟嘘P(guān)系是:
UIView 的某個(gè)負(fù)責(zé)動(dòng)畫的對象持有block,block 持有了self因?yàn)?self 并不持有 block,所以就沒有循環(huán)引用產(chǎn)生,因?yàn)榫筒恍枰褂?weak self 了。
[UIView animateWithDuration:0.2 animations:^{
self.alpha = 1;
}];
當(dāng)動(dòng)畫結(jié)束時(shí),UIView會(huì)結(jié)束持有這個(gè) block,如果沒有別的對象持有block的話,block 對象就會(huì)釋放掉,從而 block會(huì)釋放掉對于 self 的持有。整個(gè)內(nèi)存引用關(guān)系被解除。
在使用 block 的時(shí)候,為了避免產(chǎn)生循環(huán)引用,通常需要使用 weakSelf 與 strongSelf,為什么 block 里面還需要寫一個(gè) strong self,如果不寫會(huì)怎么樣?
在 block 中先寫一個(gè) strong self,其實(shí)是為了避免在 block 的執(zhí)行過程中,突然出現(xiàn) self 被釋放的尷尬情況。通常情況下,如果不這么做的話,還是很容易出現(xiàn)一些奇怪的邏輯,甚至閃退。
我們以AFNetworking中的AFNetworkReachabilityManager.m的一段代碼舉例:
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {strongSelf.networkReachabilityStatusBlock(status);
}
};
如果沒有strongSelf的那行代碼,那么后面的每一行代碼執(zhí)行時(shí),self都可能被釋放掉了,這樣很可能造成邏輯異常。
特別是當(dāng)我們正在執(zhí)行 strongSelf.networkReachabilityStatusBlock(status); 這個(gè) block閉包時(shí),如果這個(gè) block 執(zhí)行到一半時(shí) self 釋放,那么多半情況下會(huì) Crash。
weak 的內(nèi)部實(shí)現(xiàn)原理
- weak 變量在引用計(jì)數(shù)為0時(shí),會(huì)被自動(dòng)設(shè)置成 nil,這個(gè)特性是如何實(shí)現(xiàn)的?
《Objective-C高級編程》一書中也介紹了相關(guān)的內(nèi)容。
簡單來說,系統(tǒng)有一個(gè)全局的 CFMutableDictionary 實(shí)例,來保存每個(gè)對象的 weak 指針列表,因?yàn)槊總€(gè)對象可能有多個(gè) weak 指針,所以這個(gè)實(shí)例的值是 CFMutableSet 類型。
剩下我們要做的,就是在引用計(jì)數(shù)變成 0 的時(shí)候,去這個(gè)全局的字典里面,找到所有的 weak 指針,將其值設(shè)置成 nil。如何做到這一點(diǎn)呢?Friday QA 上介紹了一種類似 KVO 實(shí)現(xiàn)的方式。當(dāng)對象存在 weak 指針時(shí),我們可以將這個(gè)實(shí)例指向一個(gè)新創(chuàng)建的子類,然后修改這個(gè)子類的 release 方法,在 release 方法中,去從全局的 CFMutableDictionary 字典中找到所有的 weak 對象,并且設(shè)置成 nil。我摘抄了 Friday QA 上的實(shí)現(xiàn)的核心代碼,如下:
Class subclass = objc_allocateClassPair(class, newNameC, 0);
Method release = class_getInstanceMethod(class, @selector(release));
Method dealloc = class_getInstanceMethod(class, @selector(dealloc));
class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release));
class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc));
objc_registerClassPair(subclass);
以下代碼運(yùn)行結(jié)果如何
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
只能輸出1,然后線程主線程死鎖
因?yàn)橹骶€程阻塞。
dispatch_async(dispatch_get_main_queue(), ^{
用async異步就不會(huì)掐死線程了
});
( 不管是同步函數(shù)或者是異步函數(shù),都會(huì)將block里面的內(nèi)容派遣到對應(yīng)的隊(duì)列的最下面。,我的理解是,如果是異步的情況下,輸出順序應(yīng)該是1-3-2,,在主線程隊(duì)列后插入了一個(gè)Block,在log“3”之后執(zhí)行。 所以在主線程同步的情況下變成了 要執(zhí)行l(wèi)og“2”, 先執(zhí)行l(wèi)og“3”, 但是log“2”的執(zhí)行是主線程同步,所以在log“2”執(zhí)行完之前,log“3”不會(huì)執(zhí)行,所以會(huì)造成死鎖)
這個(gè)寫法會(huì)出什么問題: @property (copy) NSMutableArray *array;
兩個(gè)問題:1、添加,刪除,修改數(shù)組內(nèi)的元素的時(shí)候,程序會(huì)因?yàn)檎也坏綄?yīng)的方法而崩潰.因?yàn)?copy 就是復(fù)制一個(gè)不可變 NSArray 的對象;2、使用了 atomic 屬性會(huì)嚴(yán)重影響性能 ;
第1條的相關(guān)原因在下文中有論述《用@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用 copy 關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問題?》 以及上文《怎么用 copy 關(guān)鍵字?》也有論述。
比如下面的代碼就會(huì)發(fā)生崩潰
// .h文件
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// 下面的代碼就會(huì)發(fā)生崩潰
@property (nonatomic, copy) NSMutableArray *mutableArray;
// .m文件
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// 下面的代碼就會(huì)發(fā)生崩潰
NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];
接下來就會(huì)奔潰:
-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460