Objective c 使用NSOperation子类(ARC)对主线程的块回调

Objective c 使用NSOperation子类(ARC)对主线程的块回调,objective-c,ios,grand-central-dispatch,automatic-ref-counting,Objective C,Ios,Grand Central Dispatch,Automatic Ref Counting,这个问题类似于自动引用计数 我有一个NSOperation子类,它接受一个块参数,该块参数用于回调主(UI)线程。我最初的意图是在后台执行一些操作,然后使用dispatch\u async和主队列执行回调 原址: @interface MySubclass : NSOperation { @protected dispatch_block_t _callback; } - (id)initWithCallback:(dispatch_block_t)callback; @end @

这个问题类似于自动引用计数

我有一个
NSOperation
子类,它接受一个块参数,该块参数用于回调主(UI)线程。我最初的意图是在后台执行一些操作,然后使用
dispatch\u async
和主队列执行回调

原址:

@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 
删除块范围外对UIKit对象的所有引用时会出现问题。(例如,
UIViewController
从导航堆栈中弹出。)这将留下对块内对象的唯一引用,因此当块位于块被解除分配的线程上时,对象被解除分配。从主线程取消分配UIKit对象会导致应用程序崩溃,错误消息为
试图从主线程或web线程以外的线程获取web锁。这可能是从辅助线程调用UIKit的结果。正在崩溃…

作为一种解决方法,我在回调ivar中添加了一个
\u块
修饰符,并使用
dispatch\u 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

我想知道是否有更好的方法来完成这个前提。我的变通方法让人感觉不舒服,我不喜欢队列中的几个操作都在等待主线程的启动后才能完成。

如果您需要确保回调运行,即使控制器已从堆栈中弹出,那么您的变通方法是正确的

但是,如果您确实只需要在控制器仍然存在的情况下运行回调,那么在回调中使用弱引用以确保块本身首先不会保留控制器将更简单。它看起来像这样:

- (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
}

API的用户应该维护对UIView和任何其他存在此问题的对象的弱引用。回调将不再保留UIView。在块内,他们应该将弱引用指定给强引用,测试该强引用是否为零,并适当地进行操作


视图控制器应注意不要不必要地实例化其视图。在访问
[self-view]
之前,请始终使用
[self-isview]
。(这也适用于
UITableView
子类中的
[self tableView]
,因为这只是
视图
的正确别名)

另外,我遇到了您在代码末尾检查的类型的死锁,因此,我现在在主线程上使用一个helper函数进行dispatch_sync:我不一定需要运行回调,但我正在尝试更新一个现有的项目,并且仍然需要支持ios4.x。不幸的是,在4.x上,您必须使用
\uuuuuuuuunsaretained
而不是
\uuuuuuuu-weak
。还有人有什么想法吗?感谢到目前为止的反馈!