【问题标题】:NSOperation running but missing from NSOperationQueueNSOperation 正在运行但从 NSOperationQueue 中丢失
【发布时间】:2012-03-16 11:03:04
【问题描述】:

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

该结构是一个视图控制器,它从网络上异步加载一组图像并对其进行一些更改。相关(匿名)摘录如下:

@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];
    }
}

观察到的流程如下:

  • 显示视图控制器,调用 init 和 viewDidAppear 开始操作。
    • [mOperationQueue 操作] 只包含一个元素;
  • 不久之后,操作进入 main 和
  • 视图控制器在操作完成之前由用户退出。
  • 在视图控制器上调用dealloc(因为操作保持弱引用)
    • [mOperationQueue 操作] 包含零 (!) 个元素
  • cancelAllOperations 被发送到操作队列
    • [NSOperation cancel] 未被调用,导致应用可见的虚假状态。
  • dealloc 完成
  • 操作完成
    • isCancelled 返回 false,导致僵尸调用

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

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

提前致谢。

【问题讨论】:

  • @Combuster...你能在这里分享你的工作代码吗

标签: ios multithreading nsoperation nsoperationqueue


【解决方案1】:

cancelAllOperations 不会取消已经开始的操作。它只通知操作该事实并让操作自行取消,在任何时候。因此,您可以获得加注条件。继续解除分配,你确定操作被取消之后。

【讨论】:

  • 那么如何通知操作 - [self isCancelled] 已经证明是不够的。
  • 由于您必须关心操作中的取消,您可以在那里发送通知。参照。 developer.apple.com/library/mac/documentation/Cocoa/Reference/…
  • 澄清一下:isCancelled 应该被 操作用来确定是否发起了取消操作,以便操作可以做出反应。该方法旨在向外部提供有关取消成功的信息。
  • isCancelled 的唯一用途是 in 操作,如代码所示。
  • 其他方法:您尝试使用isCancelled 来确定操作是否已完成。但是,您应该使用它来确定是否请求取消
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多