2013-04-30 65 views
0

壞訪問看到這個代碼示例:GCD - 在主隊列

dispatch_queue_t downloadQueue=dispatch_queue_create("test", NULL); 

     dispatch_async(downloadQueue, ^{ 

      //do some core data fetching stuff 
      //create UIImage    

      //Need to go back to the main thread since this is UI related 
      dispatch_async(dispatch_get_main_queue(), ^{ 

        if(someView) 
        { 
         [someView addSubview:self]; 
        } 
       } 

      }); 
     }); 
     dispatch_release(downloadQueue); 

如果「someView」不這段代碼的主線程部分運行的時間有哪些?顯然這會導致EXC_BAD_ACCESS崩潰,但我想知道處理這種情況的最佳方法是什麼。當用戶導航到需要幾秒鐘加載的頁面時,通常會發生這種情況,但在當前頁面仍在加載時決定返回到上一頁。

我可以想象在嘗試添加子視圖之前需要檢查某種全局標誌,但這似乎很難。現在

+2

如果你使用ARC並且'someView'被聲明爲'weak'引用,那麼如果對象被釋放,它將是'nil'。這將避免保持對不再存在的視圖的引用的問題。 – rmaddy 2013-04-30 16:19:38

+0

這是正確的。我將該屬性定義爲「分配」而不是弱。改變爲弱解決了這個問題。 – soleil 2013-04-30 16:33:58

+0

在ARC中使用「assign」有效地消除了ARC的所有優勢! :) – matt 2013-04-30 17:08:11

回答

0
dispatch_async(downloadQueue, ^{ 
    UIView* v = someView; 

,如果在這一刻一直辦下去,如果你正在使用ARC,v是零,您可以測試這一點。另一方面,如果存在,並且您正在使用ARC,那麼v就是一個強烈的參考,並且對於塊嵌套的其餘部分它不會失去存在。然後,您可以(在此時或之後在塊的主線程部分中)詢問v.window以發現視圖是否仍在界面中;如果沒有,這是不值得的。

+0

如果使用ARC,那麼執行:'__weak UIView * v = someView'解決了這個問題。只要'v'的對象引用被解除分配,'v'將被自動設置爲'nil'。 – rmaddy 2013-04-30 17:05:53

+0

@rmaddy不是線程安全的。在塊運行時,'someView'的狀態可能會改變*。因此,沒有測試是有效的:你可以說'if(v)'並且得到一個非零的'v',但是通過從另一個線程中取消分配''v''從你之下抽出'v'。這就是爲什麼你應該總是通過塊內的強引用重新捕獲:如果它是非零*然後*,它將在塊的其餘部分保持非零。 – matt 2013-04-30 17:10:58

0
// Capture a strong reference to someView, to make sure it's still around later on. 
__block UIView *v = someView; 

//Need to go back to the main thread since this is UI related 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [v addSubview:self] 
    // Release v (assuming ARC). If nothing else has retained someView, this means 
    // that someView will be deallocated - but we're on the main thread, 
    // so that's fine. What we don't want is a background dealloc. 
    v = nil; 
}); 

OR

// Capture a strong reference to someView, to make sure it's still around later on. 
__weak UIView *weakRef = someView; 


//Need to go back to the main thread since this is UI related 
dispatch_async(dispatch_get_main_queue(), ^{ 
    // This is thread-safe because someView should only be de-alloced on the main thread. 
    // consequently our access to weakRef is safe. 
    UIView *strongRef = weakRef; 
    [strongRef addSubview:self]; 
}); 

什麼不可以做的就是這個。

UIView *strongRef = whatever; 
    dispatch_async(downloadQueue, ^{ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [someView addSubview:self] 
     }); 
     // If, by the time we get here, the dispatch to the main queue has already run, 
     // then we will send a release to someView on a background thread. If it's the last 
     // remaining reference - and it might be, unlikely as it is, then we just dealloced 
     // a UIView in the background. This is bad. 
    });