【问题标题】:Concurrent NSOperation and how to set isFinished and isExecuting?并发 NSOperation 以及如何设置 isFinished 和 isExecuting?
【发布时间】:2015-01-26 16:11:55
【问题描述】:

我正在尝试使用 NSOperations 拆分我的程序流。我正在使用 Parse 框架制作一个简单的消息传递应用程序。我想显示一些消息,然后删除它们。除非删除操作完成,否则不应调用显示消息,因此我想尝试使用 NSQueue 并向其添加 displayMessages 操作,然后添加 deleteMessages 操作(下面命名为 MyOperation)。我了解并发操作意味着它们只会以队列方式一个接一个地执行。下面是我的删除方法代码。有没有办法手动告诉操作它已完成,即设置 isFinished 或 isExecuting?

// MyOperation.h
@interface MyOperation : NSOperation {
@property (strong, nonatomic) NSMutableArray *toDelete;
}
@end
And the implementation:

// MyOperation.m
@implementation MyOperation


- (id)initWithArray:(NSMutableArray *)array
{
    self = [super init];
    if (self == nil)
        return nil;

    _toDelete=array;

}

- (void)main {
    if ([self isCancelled]) {
        NSLog(@"** operation cancelled **");
    }



//how do I get main to finish execution ONLY after deleteAllInBackground has finished? 


[PFObject deleteAllInBackground:self.toDelete];

    if ([self isCancelled]) {
        NSLog(@"** operation cancelled **");
    }


    NSLog(@"Operation finished");
}


@end

现在上面的这段代码不能解决我的问题。它会将操作排队,但即使 deleteAllInBackground 仍在运行,这个操作也会完成。真的很感激这里的一些帮助!谢谢


其他可能的解决方案:

-(void)receivedMessage
{
    NSLog(@"push!");
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        [self displayMessages];
        dispatch_async(dispatch_get_main_queue(), ^(void){
            if([self.toDelete count]>0) {
                [PFObject deleteAllInBackground:self.toDelete];

            }


        });
    });



}

【问题讨论】:

    标签: ios xcode nsoperation nsoperationqueue


    【解决方案1】:

    我建议你使用dispatch_async,如下所示;

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        dispatch_async(dispatch_get_main_queue(), ^(void){
            // Display messages
        });
        // Delete messages here
    });
    

    如果您必须使用NSOperationQueue,那么我建议您使用KVO 来获取任务完成通知;设置队列时,请执行以下操作:

    [self.deleteQueue addObserver:self forKeyPath:@"delete-operations" options:0 context:NULL];
    

    然后在您的observeValueForKeyPath 中执行此操作:

    - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                         change:(NSDictionary *)change context:(void *)context {
        if (object == self.deleteQueue && [keyPath isEqualToString:@"delete-operations"]) {
            if ([self.queue.operations count] == 0) {
                // Delete operation done
                // Display messages here
            }
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object 
                               change:change context:context];
         }
    }
    

    [编辑]

    -(void)receivedMessage {
    @synchronized(self) {
        NSLog(@"push!");
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            [self displayMessages];
            dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
                if([self.toDelete count]>0) {
                    // this deletion doesn't matter if background or on main thread as it's already in background queue
                    [PFObject deleteAllInBackground:self.toDelete];
                }
            });
        });
    }
    }
    

    【讨论】:

    • 我需要先显示然后删除然后再显示然后删除等等。使用上面的代码是否意味着我需要交换代码?顶部有显示调用,下方有删除调用?
    • 是的,您需要交换代码(我编辑过),但想法是在后台队列中执行删除操作并在主队列中显示。希望对您有所帮助。
    • 使用您的方法用代码编辑了我的问题。这看起来好吗?我需要运行 deleteAllInBackground 还是 deleteAll(主线程)?不知道我需要在那里选择什么。
    • 查看已编辑。您必须在主线程更改 UI 时调用显示消息。
    • 使用最后编辑的 receivedMessage。它应该对您有用,并且不会阻塞 UI!
    【解决方案2】:

    如果您想阻塞当前线程直到删除完成,请使用deleteAll 而不是deleteAllInBackground

    【讨论】:

    • 我不推荐这个,因为它会带来不愉快的 UI 体验!
    • 性能方面通常不推荐,对吧?我想我试过了,控制台给了我一些警告。它会阻止 UI 正常运行吗?
    • 不建议阻塞主队列。如果您希望它长时间运行,请不要将您的 NSOperation 安排在主队列中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多