【问题标题】:iPhone - return from an NSOperationiPhone - 从 NSOperation 返回
【发布时间】:2009-11-20 13:48:28
【问题描述】:

我正在使用 NSOperation 的子类来执行一些后台进程。我希望在用户单击按钮时取消操作。

这是我的 NSOperation 子类的样子

- (id)init{
    self = [super init];
    if(self){
        //initialization code goes here
        _isFinished = NO;
        _isExecuting = NO;
    }

    return self;
}

- (void)start
{
    if (![NSThread isMainThread])
    {
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }
    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];

    //operation goes here
}

- (void)finish{
    //releasing objects here

    [self willChangeValueForKey:@"isExecuting"];
    [self willChangeValueForKey:@"isFinished"];

    _isExecuting = NO;
    _isFinished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

- (void)cancel{
    [self willChangeValueForKey:@"isCancelled"];

    [self didChangeValueForKey:@"isCancelled"];
    [self finish];
}

这就是我将此类的对象添加到队列并监听 KVO 通知的方式

operationQueue = [[NSOperationQueue alloc] init]; [操作队列 setMaxConcurrentOperationCount:5]; [operationQueue addObserver:self forKeyPath:@"operations" options:0 context:&OperationsChangedContext];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == &OperationsChangedContext) {
        NSLog(@"Queue size: %u", [[operationQueue operations] count]);
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

要取消操作(例如单击按钮),我尝试调用 -cancel,但没有任何区别。也尝试调用 -finish 但即使这样也不会改变任何东西。

每次我向队列添加操作时,队列大小只会增加。调用完成(使用 NSLog 语句检查),但它并没有真正结束操作。我仍然不是很自信我做得对

谁能告诉我哪里出错了?

非常感谢

【问题讨论】:

    标签: iphone multithreading nsoperation


    【解决方案1】:

    来自NSOperation Class Reference

    取消操作不会立即强制它停止正在执行的操作。尽管所有操作都需要遵守 isCancelled 返回的值,但您的代码必须明确检查此方法返回的值并根据需要中止

    cancel 方法实际上不会取消操作,除非您的实现强制执行此操作。同样,来自相关的section

    - (void)cancel

    此方法不会强制您的操作代码停止。相反,它会更新对象的内部标志以反映状态的变化。

    【讨论】:

    • 是的,请阅读。但是我在哪里检查 isCancelled?你不能在 NSOperation 中触发计时器!
    • 您当然不必轮询标志更改,您只需在取消方法被调用时执行中止过程?
    • 这里请多多包涵。我在 NSOperation 类中调用了一个 AVAudioPlayer 的播放方法。在取消方法中,我停止了播放器,但接下来呢?队列中的操作数仍然显示为相同。
    • 我认为将 isFinished 设置为 true 应该会自动使操作出队,但您似乎已经这样做了,所以这里可能发生了其他事情?值得在调试器中单步执行并检查值以确定。
    【解决方案2】:

    您只需要以下内容即可实现:

    在你的 NSOperation 子类中,添加到 main 方法

     while (! self.isCancelled) {
      [NSThread sleepForTimeInterval:1];
     }
    

    在 GUI 类中,您需要 NSOperation 子类的实例变量,在管理按钮的方法中,您取消 NSOperation 子类。例如:

    - (IBAction) clickButton: (UIBarButtonItem *) item{
     [myOperation cancel]; 
    }
    

    【讨论】:

    • 为什么要投反对票?你的线程不应该在循环运行吗??
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 2017-01-14
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多