多線程調(diào)用問(wèn)題2

前言

最近遇到一個(gè)崩潰,都是一些基礎(chǔ)問(wèn)題沒(méi)注意引起的。查找問(wèn)題的時(shí)候還是花了一些時(shí)間,感覺(jué)還是有必要記錄一下。

崩潰堆棧
Operating system: iOS
                  10.3.2 14F89
CPU: arm64
     2 CPUs

Crash reason:  EXC_BAD_ACCESS / KERN_INVALID_ADDRESS
Crash address: 0x70747488
Process uptime: 17380 seconds

Thread 23 (crashed)
 0  libobjc.A.dylib!objc_retain + 0x10
     x0 = 0x0000000174af0000    x1 = 0x00000001969e0453
     x2 = 0x00000000000001e8    x3 = 0x0000000000000001
     x4 = 0x0000000000000001    x5 = 0x0000000000000001
     x6 = 0x0000000000000000    x7 = 0x0000000000000000
     x8 = 0x0000000370747468    x9 = 0x0000000000000000
    x10 = 0x0000000111621c00   x11 = 0x00000171000001ff
    x12 = 0x0000000111622130   x13 = 0x000005a1011a12d5
    x14 = 0x0000000000000004   x15 = 0x0000000000000b2d
    x16 = 0x000000018e7dca80   x17 = 0x0000000100124ee8
    x18 = 0x0000000000000000   x19 = 0x00000001b4a6d500
    x20 = 0x00000001057ae808   x21 = 0x000000016e1630e0
    x22 = 0x00000001057ae620   x23 = 0x000000016e1630e0
    x24 = 0xffffffffffffffff   x25 = 0x00000001b6037360
    x26 = 0x0000000008000000   x27 = 0x00000001b6037330
    x28 = 0x0000000000000000    fp = 0x000000016e162d40
     lr = 0x000000018e7dcb10    sp = 0x000000016e162d20
     pc = 0x000000018e7e81a0
    Found by: given as instruction pointer in context
 1  libobjc.A.dylib!objc_getProperty + 0x8c
     fp = 0x000000016e162e10    lr = 0x00000001001238a0
     sp = 0x000000016e162d50    pc = 0x000000018e7dcb10
    Found by: previous frame's frame pointer
 2  QingYu!__48-[BSWebImageView _loadCacheImageIfNeed:success:]_block_invoke [BSWebImageView.m : 222 + 0xc]
     fp = 0x000000016e162e30    lr = 0x000000018ec229e0
     sp = 0x000000016e162e20    pc = 0x00000001001238a0
    Found by: previous frame's frame pointer
 3  libdispatch.dylib!_dispatch_call_block_and_release + 0x14
     fp = 0x000000016e162e50    lr = 0x000000018ec229a0
     sp = 0x000000016e162e40    pc = 0x000000018ec229e0
    Found by: previous frame's frame pointer
 4  libdispatch.dylib!_dispatch_client_callout + 0xc
     fp = 0x000000016e162ec0    lr = 0x000000018ec32bac
     sp = 0x000000016e162e60    pc = 0x000000018ec229a0
    Found by: previous frame's frame pointer
 5  libdispatch.dylib!_dispatch_root_queue_drain + 0x374
     fp = 0x000000016e162ee0    lr = 0x000000018ec327d0
     sp = 0x000000016e162ed0    pc = 0x000000018ec32bac
    Found by: previous frame's frame pointer
 6  libdispatch.dylib!_dispatch_worker_thread3 + 0x78
     fp = 0x000000016e162f70    lr = 0x000000018ee2b100
     sp = 0x000000016e162ef0    pc = 0x000000018ec327d0
    Found by: previous frame's frame pointer
 7  libsystem_pthread.dylib!_pthread_wqthread + 0x444
     fp = 0x0000000000000000    lr = 0x000000018ee2acac
     sp = 0x000000016e162f80    pc = 0x000000018ee2b100
    Found by: previous frame's frame pointer
 8  libsystem_pthread.dylib!start_wqthread + 0x0
     fp = 0x0000000000000000    lr = 0x0000000000000000
     sp = 0x000000016e162f80    pc = 0x000000018ee2acac
    Found by: previous frame's frame pointer

初步分析

從崩潰堆??吹绞?EXC_BAD_ACCESS , 非法地址訪問(wèn)。就是我們常說(shuō)的野指針訪問(wèn)。第一反應(yīng)就是對(duì)象已經(jīng)釋放了。

相關(guān)代碼

    if (self.asyncLoadImage) {
        WEAKIFYSELF;
        
        CGSize viewSize = weak_self.bounds.size;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            if (![urlRequest.URL.absoluteString isEqualToString:weak_self.request.absoluteString]) {
                return;
            }
            UIImage *cachedImage = [UIImage imageWithContentsOfFile:imageFilePath];
            
            if (weak_self.needResizeImage) {
                if (weak_self.needResizeImage && !CGSizeEqualToSize(CGSizeZero,viewSize) ) {
                    //TODO: need resize callback.
                    cachedImage = [UIImage reSizeImage:cachedImage toSize:viewSize];
                }
            }

崩潰指向有問(wèn)題的代碼行是 :

if (![urlRequest.URL.absoluteString isEqualToString:weak_self.request.absoluteString]) { 

第一反應(yīng)都是認(rèn)為 self 對(duì)象出問(wèn)題了。但 self 是弱指針,銷毀后會(huì)置空,而且空調(diào)用是沒(méi)問(wèn)題的。因此,我們就懷疑 self.request 對(duì)象,會(huì)不會(huì)是因?yàn)閷傩远x成 assign 導(dǎo)致的呢?

@property (nonatomic, strong) NSURL *request;

request 屬性定義就強(qiáng)引用, 理論上應(yīng)該也不會(huì)有問(wèn)題才對(duì)。難道在訪問(wèn)他的時(shí)候,突然間銷毀了?
后來(lái)我們注意到訪問(wèn)屬性的地方是在一個(gè)global queue 里面, 而修改 self.request的操作 卻在主線程。并且修改的方式是通過(guò) 私有變量 的方式修改 _request = urlRequest.URL; 這種操作實(shí)際上是執(zhí)行

1, [_request release]
2, _request = urlRequest;

因?yàn)槭嵌嗑€程原因,在執(zhí)行了第一步后發(fā)生線層切換, 此時(shí) _request 對(duì)象 是野指針狀態(tài),其他任意一個(gè)線程對(duì)它的任何操作都有可能會(huì)出問(wèn)題。

解決問(wèn)題

1,把屬性修飾符改成 atom @property (atomic, strong) NSURL *request;
2,修改屬性值的地方改成 屬性方式修改 self.request = urlRequest

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,629評(píng)論 1 32
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,801評(píng)論 0 73
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,590評(píng)論 0 6
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛(ài)DE問(wèn)候閱讀 1,836評(píng)論 0 4
  • 1.設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式,并簡(jiǎn)要敘述?設(shè)計(jì)模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,296評(píng)論 0 12

友情鏈接更多精彩內(nèi)容