最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS中多線程的經(jīng)典崩潰總結(jié)大全

 更新時間:2017年12月18日 10:47:29   作者:vedon_fu  
這篇文章主要給大家介紹了關(guān)于iOS中多線程的一些經(jīng)典崩潰的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。

前言

iOS崩潰是讓iOS開發(fā)人員比較頭痛的事情,app崩潰了,說明代碼寫的有問題,這時如何快速定位到崩潰的地方很重要。調(diào)試階段是比較容易找到出問題的地方的,但是已經(jīng)上線的app并分析崩潰報告就比較麻煩了。

本文將給大家總結(jié)介紹關(guān)于iOS中多線程的一些經(jīng)典崩潰,下面話不多說了,來一起看看詳細的介紹吧。

0x0 Block 回調(diào)的崩潰

在MRC環(huán)境下,使用Block 來設置下載成功的圖片。當self釋放后,weakSelf變成野指針,接著就悲劇了

 __block ViewController *weakSelf = self;
 [self.imageView imageWithUrl:@"" completedBlock:^(UIImage *image, NSError *error) { 
 NSLog(@"%@",weakSelf.imageView.description);
 }];

0x1 多線程下Setter 的崩潰

Getter & Setter 寫多了,在單線程的情況下,是沒有問題的。但是在多線程的情況下,可能會崩潰。因為[_imageView release]; 這段代碼可能會被執(zhí)行兩次,oops!

UIKit 不是線程,所以在不是主線程的地方調(diào)用UIKit 的東西,有可能在開發(fā)階段完全沒問題,直接免測。但是一到線上,崩潰系統(tǒng)可能都是你的崩潰日志。Holy shit!

解決辦法:通過hook 住setNeedsLayout,setNeedsDisplay,setNeedsDisplayInRect來檢查當前調(diào)用的線程是否是主線程。

- (void)setImageView:(UIImageView *)imageView
{
 if (![_imageView isEqual:imageView])
 {
 [_imageView release];
 _imageView = [imageView retain];
 }
}

0x2 更多Setter 類型的崩潰

property 的屬性,寫的最多的就是nonatomic,一般情況下也是沒有問題的!

@interface ViewController ()
@property (strong,nonatomic) NSMutableArray *array;
@end

跑一下下面這段代碼,你會看到:
malloc: error for object 0x7913d6d0: pointer being freed was not allocated

for (int i = 0; i < 100; i++) {
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  self.array = [[NSMutableArray alloc] init];
 });
 } 

原因就是:對象被重復relaese 了。查看一下runtime 源碼


解決辦法:屬性聲明為atomic.

一個更為常見的例子:

if(handler == nil)
{
 hander = [[Handler alloc] init];
}
return handler;

如果A,B兩個線程同時訪問到if語句, 此時handler == nil條件滿足, 兩個線程都走到下一句初始化實例.

此時A線程先完成初始化并賦值(這個實例我們叫它a), 然后繼續(xù)往后走到其他邏輯.而這時候, B線程開始做初始化并賦值(這個實例我們叫它b), handler將指向B線程初始化出來的對象. 而A初始化出來的實例a因為引用計數(shù)減少1(減少到0)而被釋放. 但在A線程中, 代碼還會嘗試訪問a所在的地址, 這個地址里的內(nèi)容因為被釋放而變得無法預測, 從而導致野指針.

問題還有一個很關(guān)鍵的點, 在一個對象的某個方法的調(diào)用過程中, 這個對象的引用計數(shù)并不會增加, 到導致它如果被釋放, 后續(xù)的執(zhí)行過程中對這個對象的訪問就可能會導致野指針[1].

Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x12345678
Triggered by Thread: 1

簡單加個鎖就可以解決問題了:

 @synchronized(self){
 if(handler == nil)
 {
  hander = [[Handler alloc] init];
 }
 }
return handler;

0x3 多線程下對變量的存取

if (self.xxx) {
 [self.dict setObject:@"ah" forKey:self.xxx];
}

大家第一眼看到這樣的代碼,是不是會認為是正確的?因為在設置key的時候已經(jīng)提前進行了self.xxx為非nil的判斷,只有非nil得情況下才會執(zhí)行后續(xù)的指令。但是,如上代碼只有在單線程的前提下才是正確的。

假設我們將上述代碼目前執(zhí)行的線程為Thread A,當我們執(zhí)行完if (self.xxx)的語句之后,此時CPU將執(zhí)行權(quán)切換給了Thread B,而這個時候Thread B中調(diào)用了一句self.xxx = nil。 使用局部變量可以解決這個問題

__strong id val = self.xxx;
if (val) {
 [self.dict setObject:@"ah" forKey:val];
}

這樣,無論多少線程嘗試對self.xxx進行修改,本質(zhì)上的val都會保持現(xiàn)有的狀態(tài),符合非nil的判斷。

0x4 dispatch_group 的崩潰

dispatch_group_enter 和 leave 必須是匹配的,不然就會crash . 在多資源下載的時候,往往需要使用多線程并發(fā)下載,全部下載完之后通知用戶。開始下載,dispatch_group_enter ,下載完成dispatch_group_leave 。 非常簡單的流程,但是當代碼復雜到一定程度或者是使用了一些第三方庫的時候,就很大可能出問題。

dispatch_group_t serviceGroup = dispatch_group_create();
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(), ^{
 NSLog(@"Finish downloading :%@", downloadUrls);
});
// t 是一個包含一堆字符串的數(shù)組 
[downloadUrls enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
 dispatch_group_enter(serviceGroup);
 SDWebImageCompletionWithFinishedBlock completion =
 ^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
  dispatch_group_leave(serviceGroup);
  NSLog(@"idx:%zd",idx);
 };
 [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString: downloadUrls[idx]]      options:SDWebImageLowPriority      progress:nil             completed:completion];
}];

使用多線程進行并發(fā)下載,直到所有圖片都下載完成(可以失?。┻M行回調(diào),其中圖片下載使用的是SDWebImage.發(fā)生崩潰的場景是:有10 張圖片,分開兩次下載(A & B)。其中在B組里面有一張圖片和A組下載的圖片重復了。假設A組下載對應GroupA ,B組GroupB

下面截取SDWebImage源碼:

dispatch_barrier_sync(self.barrierQueue, ^{
 SDWebImageDownloaderOperation *operation = self.URLOperations[url];
 if (!operation) {
  operation = createCallback();
  // ****注意這行****
  self.URLOperations[url] = operation;
  __weak SDWebImageDownloaderOperation *woperation = operation;
  operation.completionBlock = ^{
   SDWebImageDownloaderOperation *soperation = woperation;
   if (!soperation) return;
   if (self.URLOperations[url] == soperation) {
    [self.URLOperations removeObjectForKey:url];
   };
  };
 }
// ****注意這行****
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
}

SDWebImage的下載器會根據(jù)URL做下載任務對應NSOperation映射,相同的URL會映射到同一個未執(zhí)行的NSOperation。當A組圖片下載完成后,相同的url 回調(diào)是 GroupB 而不是Group A。此時Group B的計數(shù)為1 。當B 組圖片全部下載完后,結(jié)束計數(shù)為 5+1 。因為enter 的次數(shù)為5 ,leave 的次數(shù)為6 ,因此會崩潰!

0x5 最后一個持有者釋放后的崩潰

對象A被 manager 持有,在A中調(diào)用[Manager removeObjectA] 。A對象的retainCount -1, 當retainCount 等于零時,對象A已經(jīng)開始釋放了。在調(diào)用removeObjectA 后,緊接著調(diào)用[self doSomething] ,就會崩潰。

- (void)finishEditing
{
 [Manager removeObject:self];
 [self doSomething];
}

這種情況一般會發(fā)生在數(shù)組或者字典包含對象,而且是對象的最后持有者。當在對象處理不好,就會有上面的崩潰。還有一種情況就是,當數(shù)組或者字典里面的對象已經(jīng)被釋放了,當遍歷數(shù)組或者取字典里面的值發(fā)生崩潰。這種情況,會讓人很崩潰,因為有時候堆棧是這樣的:

Thread 0 Crashed:
0 libobjc.A.dylib     0x00000001816ec160 _objc_release :16 (in libobjc.A.dylib)
1 libobjc.A.dylib     0x00000001816edae8 __ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv :508 (in libobjc.A.dylib)
2 CoreFoundation     0x0000000181f4c9fc __CFAutoreleasePoolPop :28 (in CoreFoundation)
3 CoreFoundation     0x0000000182022bc0 ___CFRunLoopRun :1636 (in CoreFoundation)
4 CoreFoundation     0x0000000181f4cc50 _CFRunLoopRunSpecific :384 (in CoreFoundation)
5 GraphicsServices    0x0000000183834088 _GSEventRunModal :180 (in GraphicsServices)
6 UIKit       0x0000000187236088 _UIApplicationMain :204 (in UIKit)
7 Tmall4iPhone     0x00000001000b7ae4 main main.m:50 (in Tmall4iPhone)
8 libdyld.dylib     0x0000000181aea8b8 _start :4 (in libdyld.dylib)

產(chǎn)生這種堆??赡艿膱鼍笆牵?br />

釋放Dictionary的時候,某個值(value)因為被其他代碼提前釋放變成野指針, 此時再次被釋放觸發(fā)Crash. 如果可以在每個Dictionary釋放的時候, 把所有的key/value打出來, 如果某個key/value剛好被打出來之后, crash就發(fā)生了, 那么掛就掛在剛被打出來的key/value上.

0x6 對象的釋放線程要和它處理事情的線程一致

對象A在主線程監(jiān)聽Notification事件,如果這個對象被其它線程釋放了。此刻,如果對象A 正在執(zhí)行notification 相關(guān)的操作,再訪問對象相關(guān)資源就野指針了,發(fā)生crash.

0x7 performSelector:withObject:afterDelay:

調(diào)用此方法,如果不是在主線程,那么必須要確保當前線程的ruuloop是存在的,performSelector_xxx_afterDelay 依賴runlopp才能執(zhí)行。另外使用 performSelector:withObject:afterDelay:cancelPreviousPerformRequestsWithTarget 組合的時候要小心。

  • afterDelay會增加receiver的引用計數(shù),cancel則會對應減一
  • 如果在receiver的引用計數(shù)只剩下1 (僅為delay)時,調(diào)用cancel之后會立即銷毀receiver,后續(xù)再調(diào)用receiver的方法就會crash
__weak typeof(self) weakSelf = self;
[NSObject cancelPreviousPerformRequestsWithTarget:self];
if (!weakSelf)
{
//NSLog(@"self被銷毀");
 return;
}
[self doOther];

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • iOS中UILabel text兩邊對齊的實現(xiàn)代碼

    iOS中UILabel text兩邊對齊的實現(xiàn)代碼

    本文通過一段實例代碼給大家介紹了ios中uilabel text兩邊對齊的實現(xiàn)方法,非常不錯,具有參考借鑒價值,需要的朋友參考下
    2017-01-01
  • iOS文本的多語言適配以及實踐指南

    iOS文本的多語言適配以及實踐指南

    項目開發(fā)中考慮到不同國家的用戶,不同國家的語言,因而在APP里面做了多語言,所以下面這篇文章主要給大家介紹了關(guān)于iOS文本的多語言適配以及實踐的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • iOS小技能之字典轉(zhuǎn)模及對象相等性示例詳解

    iOS小技能之字典轉(zhuǎn)模及對象相等性示例詳解

    這篇文章主要為大家介紹了iOS小技能之字典轉(zhuǎn)模及對象相等性示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • iOS開發(fā)中Swift逃逸閉包知識

    iOS開發(fā)中Swift逃逸閉包知識

    這篇文章主要介紹了iOS開發(fā)中Swift逃逸閉包的相關(guān)知識點以及需要注意的地方,需要的朋友收藏下吧。
    2018-02-02
  • iOS 進度條、加載、安裝動畫的簡單實現(xiàn)

    iOS 進度條、加載、安裝動畫的簡單實現(xiàn)

    這篇文章主要介紹了iOS 進度條、加載、安裝動畫的簡單實現(xiàn),非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • iOS中FMDB事務實現(xiàn)批量更新數(shù)據(jù)

    iOS中FMDB事務實現(xiàn)批量更新數(shù)據(jù)

    這篇文章主要為大家詳細介紹了iOS中FMDB事務實現(xiàn)批量更新數(shù)據(jù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • iOS中鍵盤 KeyBoard 上添加工具欄的方法

    iOS中鍵盤 KeyBoard 上添加工具欄的方法

    大iOS中 鍵盤 KeyBoard 上怎么添加工具欄呢?大致思路是提前創(chuàng)建好工具欄,在鍵盤彈出的時候?qū)⒐ぞ邫陲@示出來,在鍵盤消失的時候讓工具欄隱藏。具體實現(xiàn)代碼大家參考下本文吧
    2017-08-08
  • iOS毛玻璃效果的實現(xiàn)及圖片模糊效果的三種方法

    iOS毛玻璃效果的實現(xiàn)及圖片模糊效果的三種方法

    App設計時往往會用到一些模糊效果或者毛玻璃效果,iOS目前已提供一些模糊API可以讓我們方便是使用,本文給大家介紹iOS毛玻璃效果的實現(xiàn)及圖片模糊效果的三種方法,感興趣的朋友一起學習吧
    2016-01-01
  • iOS11中的定位授權(quán)的解決方法

    iOS11中的定位授權(quán)的解決方法

    本篇文章主要介紹了iOS11中的定位授權(quán)的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • iOS11上Xcode9 AppIcon 圖標不顯示

    iOS11上Xcode9 AppIcon 圖標不顯示

    升級到iOS11系統(tǒng)下自己的項目桌面app圖標不見了,是什么原因呢,經(jīng)過一番查找,終于發(fā)現(xiàn)問題所在,現(xiàn)在分享給大家
    2017-11-11

最新評論

深水埗区| 奎屯市| 江川县| 木兰县| 宣城市| 渑池县| 博客| 东兴市| 大庆市| 于都县| 铜山县| 柘城县| 宿松县| 兖州市| 新晃| 分宜县| 奉化市| 四平市| 大新县| 贵溪市| 克拉玛依市| 资兴市| 浦县| 米易县| 内黄县| 兴海县| 合川市| 邯郸县| 米易县| 甘泉县| 廊坊市| 保靖县| 顺义区| 玉溪市| 雅安市| 时尚| 徐汇区| 天长市| 广昌县| 慈利县| 杭州市|