NSOperation中的异步方法

时间:2009-10-20 17:33:56

标签: iphone asynchronous nsoperation fbconnect

我从Facebook Connect获取一些数据(使用FBConnect Objective-C 2.0框架),我正在NSOperation中完成所有这些工作。它在NSOperation中,因为我还运行了其他几个操作,这就是其中之一。

问题是所有FBConnect调用都是异步的。因此,NSOperation的主要方法快速完成,操作标记为已完成。

有没有办法克服这个问题?看来FBConnect中没有同步选项!

非常感谢,

麦克

4 个答案:

答案 0 :(得分:24)

以下是一个完整的例子。在您的子类中,在异步方法完成后,调用[self completeOperation]以转换到已完成状态。

@interface AsynchronousOperation()
// 'executing' and 'finished' exist in NSOperation, but are readonly
@property (atomic, assign) BOOL _executing;
@property (atomic, assign) BOOL _finished;
@end

@implementation AsynchronousOperation

- (void) start;
{
    if ([self isCancelled])
    {
        // Move the operation to the finished state if it is canceled.
        [self willChangeValueForKey:@"isFinished"];
        self._finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }

    // If the operation is not canceled, begin executing the task.
    [self willChangeValueForKey:@"isExecuting"];
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    self._executing = YES;
    [self didChangeValueForKey:@"isExecuting"];

}

- (void) main;
{
    if ([self isCancelled]) {
        return;
    }

}

- (BOOL) isAsynchronous;
{
    return YES;
}

- (BOOL)isExecuting {
    return self._executing;
}

- (BOOL)isFinished {
    return self._finished;
}

- (void)completeOperation {
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];

    self._executing = NO;
    self._finished = YES;

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

@end

答案 1 :(得分:6)

FBConnect来电置于“start”,而不是“main”,并管理“isFinished”{“1}}”属性。 (并返回“isExecuting”的YES

有关详细信息,请参阅Apple有关撰写concurrent NSOperations的文档。

答案 2 :(得分:0)

如果没有其他要求,请理解这一点:NSOperation的行为没有任何魔术。 NSOperationQueue仅使用关键值观察来监视操作。之所以不那么容易的唯一原因是所使用的密钥与Objective-C 2.0约定所说的密钥不同,因此标准的合成设置器将无法使用。

结果是,当您定义NSOperation子类时,需要提供asynchronousexecutingfinished。最后两个需要您的帮助才能正常工作。

听起来复杂吗?不是,只是细节。整个过程中的每个步骤都很简单且有意义,但在您正确理解所有步骤之前,它实际上不会起作用。

首先,标题:

//
//  MyOperation.h

#import <Foundation/Foundation.h>

@interface MyOperation : NSOperation

@property(readonly, getter=isAsynchronous) BOOL asynchronous;
@property(readonly, getter=isExecuting) BOOL executing;
@property(readonly, getter=isFinished) BOOL finished;

@end

您当然可以在此处将executingfinished定义为readwrite,因此在实现中无需将它们重新定义为readwrite。但是我想知道只有我的操作可以更改它们的状态。

现在执行。这里有一些步骤:

  • finishedexecuting属性重新定义为读/写。
  • 完全提供executingfinished的实现,以手动提供正确的KVO消息传递(因此isExecutingsetExecuting:isFinished和{{1} })。
  • 使用setFinished:executingfinished密钥提供存储。
  • 提供@synthesize
  • 的实现

(请注意,此代码可能会滚动一点。)

asynchronous

实际上不需要在设置器中检查// // MyOperation.m #import "MyOperation.h" @interface MyOperation() @property(readwrite) BOOL executing; @property(readwrite) BOOL finished; @end @implementation MyOperation // Provide your own start. - (void)start { if (self.cancelled) { self.finished = YES; return; } NSLog(@"Starting %@", self); self.executing = YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ NSLog(@"Finished %@", self); self.executing = NO; self.finished = YES; }); } // The rest of this is boilerplate. - (BOOL)isAsynchronous { return YES; } @synthesize executing = _executing; - (BOOL)isExecuting { @synchronized(self) { return _executing; } } - (void)setExecuting:(BOOL)executing { @synchronized(self) { if (executing != _executing) { [self willChangeValueForKey:@"isExecuting"]; _executing = executing; [self didChangeValueForKey:@"isExecuting"]; } } } @synthesize finished = _finished; - (BOOL)isFinished { @synchronized(self) { return _finished; } } - (void)setFinished:(BOOL)finished { @synchronized(self) { if (finished != _finished) { [self willChangeValueForKey:@"isFinished"]; _finished = finished; [self didChangeValueForKey:@"isFinished"]; } } } @end 。通过调用executing != _executing,盲目更改值,然后调用willChangeValueForKey,可以自动提供正确的行为。但是这种情况意味着您可以在赋值上设置一个断点,并且只有在值更改后才停止,并且我发现这在实践中调试我的操作非常有用。

我还看到通过在didChangeValueForKeyexecuting属性之上提供自定义状态来实现此目的。当然,这可以很好地工作,并且在某些方面会更好……但是比这个示例还需要更多的KVO知识,这已经足够了。

最后,请注意,操作开始后,我还没有添加对cancel的支持。为此,您必须覆盖finished(或者更正确地说,观察cancel的值)并进行处理。这会使我的简单isCancelled示例变得复杂很多。

我在命令行控制台应用程序中运行了此代码,方法是将15个操作添加到start为5的队列中,然后等待队列完成使用maxConcurrentOperationCount的操作(这就是为什么我使用背景在我的waitUntilAllOperationsAreFinished中排队dispatch_after)。这是输出:

start

答案 3 :(得分:0)

这个怎么样?

//
//  Operation.m

#import "Operation.h"

@interface Operation() 

@property (nonatomic, strong) dispatch_semaphore_t semaphore;

@end

@implementation Operation 

- (void)main {
    [self doWorkWithCompletion:^{
        dispatch_semaphore_signal(self.semaphore);
    }];    
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
}

....

@end