4

這個問題是類似於this question與自動參考計數投入。從的NSOperation子類(ARC)使用塊回調主線程

我有一個NSOperation子類,接受旨在作爲回調一個塊參數到主(UI)線程。我的初衷是在後臺執行一些操作,然後使用dispatch_async和主隊列執行回調。

原始前提:當被刪除到塊的範圍之外的UIKit的對象的所有引用出現

@interface MySubclass : NSOperation { 
@protected 
    dispatch_block_t _callback; 
} 

- (id)initWithCallback:(dispatch_block_t)callback; 

@end 

@implementation MySubclass 

- (void)main 
{ 
    // Do stuff 

    if (![self isCancelled]) { 
     dispatch_async(dispatch_get_main_queue(), _callback); 
    } 
} 

@end 

問題。 (例如,從導航堆棧彈出UIViewController)。這留下了塊內對象的唯一引用,因此當塊被解除分配的線程上時,對象被解除分配。重新分配一個對象的UIKit關閉主線程崩潰,並顯示錯誤消息Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...

變通方法是應用程序,我加了__block修正回調伊娃,和現在用dispatch_sync使釋放確保一切都在主線程上。

@interface MySubclass : NSOperation { 
@protected 
    __block dispatch_block_t _callback; 
} 
- (id)initWithCallback:(dispatch_block_t)callback; 

@end 

@implementation MySubclass 

- (void)main 
{ 
    // Do Stuff 

    if (![self isCancelled]) { 
     dispatch_block_t block = ^{ 
      _callback(); 
      _callback = nil; 
     }; 

     // Cover all our bases to prevent deadlock 
     if ([NSThread isMainThread]) block(); 
     else dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

@end 

我想知道是否有更好的方法來完成這個前提。我的解決方法讓人感覺很不舒服,而且我不喜歡這樣,我可能會在我的隊列中完成幾項操作,並在完成之前等待主線程啓動。

+0

另一方面,我遇到了在代碼結束時檢查的類型的死鎖,所以現在使用主線程上的dispatch_sync助手函數:http://stackoverflow.com/questions/5225130/grand-central-dispatch-gcd-vs-performselector-need-a-better-explanation/5226271#5226271 –

回答

4

如果您需要確保即使控制器已從堆棧中彈出,回調仍在運行,那麼您的解決方法是正確的。

但是,如果你真的只需要回調就可以運行,如果控制器還在,那麼在回調中使用弱引用將會更簡單,以確保塊本身不會保留第一個控制器地點。這將是這個樣子:

- (void)demoMethod { 
    __weak id weakSelf = self; 
    MySubclass *subclass = [[MySubclass alloc] initWithCallback:^{ 
     if (!weakSelf) { 
      return; 
     } 
     else { 
      // Do whatever the callback does here 
     } 
    }]; 

    // Do something with `subclass` here 
} 
+1

我不一定需要回調才能運行,但我試圖更新現有的項目,仍然需要支持iOS 4.x.不幸的是,在4.x中,你必須使用'__unsafe_unretained'而不是'__weak'。任何人有更多的想法?感謝迄今爲止的反饋! – sho

1

您的API的用戶應保持對UIViews和弱引用這個問題的任何其他對象。回調將不再保持UIView。在該塊內,他們應該將弱引用分配給強引用,測試該引用強對齊,並適當地執行。

視圖控制器應該注意不要不必要地實例化它們的視圖。在訪問[self view]之前始終使用[self isViewLoaded]。 (這也適用於[self tableView]UITableView子類,因爲這只是view的正確類型別名。)