NSOperation在NSOperationQueue中运行但缺失

时间:2012-03-16 11:03:04

标签: ios multithreading nsoperation nsoperationqueue

我最近一直在调试一个带有操作的僵尸问题,并发现在队列上调用cancelAllOperations并没有取消有问题的操作,事实上,即使操作仍在运行,操作队列也是空的。

该结构是一个视图控制器,异步地从Web上加载一组图像并对它们执行一些更改。相关的(匿名的)exerpts如下:

@implementation MyViewController

- (id) init
{
    (...)
    mOperationQueue = [[NSOperationQueue alloc] init];
    (...)
}

- (void) viewDidAppear:(BOOL)animated
{
    (...)
    MyNSOperation * operation = [[MyNSOperation alloc] initWithDelegate:self andData:data];
    [mOperationQueue addOperation:operation];
    [operation release];
    (...)
}

- (void) dealloc
{
    (...)
    [mOperationQueue cancelAllOperations];
    [mOperationQueue release];
    (...)
}

- (void) imagesLoaded:(NSArray *)images
{
    (...)
}

有问题的操作:

@implementation MyNSOperation

- (id) initWithDelegate:(id)delegate andData:(NSDictionary *)data
{
    self = [super init];
    if (self)
    {
        mDelegate = delegate; // weak reference
        mData = [data retain];
        (...)
    }
    return self;
}

- (void) main
{
    NSAutoReleasePool * pool = [[NSAutoReleasePool alloc] init];

    mImages = [[NSMutableArray alloc] init];
    // load and compose images
    mAlteredImages = (...)

    [self performSelectorOnMainThread:@selector(operationCompleted) withObject:nil waitUntilDone:YES];

    [pool release];
}

- (void)operationCompleted
{
    if (![self isCancelled])
    {
        [mDelegate imagesLoaded:mAlteredImages];
    }
}

观察到的流程如下:

  • 显示了viewcontroller,调用init和viewDidAppear开始操作。
    • [mOperationQueue operations]只包含一个元素;
  • 不久之后,操作进入main和
  • 在操作完成之前,用户将退出viewcontroller。
  • 在viewcontroller上调用dealloc(因为该操作保持弱引用)
    • [mOperationQueue operations]包含零(!)元素
  • cancelAllOperations被发送到操作队列
    • [NSOperation cancel]未被调用,导致app-visible伪造状态。
  • dealloc饰面
  • 操作完成
    • isCancelled返回false,导致僵尸调用

然而,NSOperationQueue的文档明确指出“操作在完成任务之前一直排队等待”。这看起来像是违约。

我通过保留对操作的引用并手动发送取消来修复崩溃,但我想知道为什么原始方法无法防止进一步的问题。有人可以对此有所了解吗?

提前致谢。

1 个答案:

答案 0 :(得分:0)

cancelAllOperations不会取消已启动的操作。它只通知操作有关该事实并让操作取消它自己,只要它想要。因此,您可以获得加薪条件。继续执行deallocacion,之后确定操作已取消。