【问题标题】:NSOperationQueue's addOperation: operation is finished and cannot be enqueued?NSOperationQueue 的 addOperation: 操作完成,不能入队?
【发布时间】:2013-05-30 19:54:05
【问题描述】:

注意:
这只是一个概念验证。
真正的后台任务将是不断请求原始数据的“HTTP Get”并通过主线程显示;按需提供。

场景:
1)按需切换后台任务(循环)。
2) 后台任务在每次迭代时通知主线程 UI。
3) 队列中仅运行一 (1) 个块操作。

作案手法
1) 使用 NSBlockOperation 包含后台代码。
2)使用区域BOOL来切换循环;通过 IBAction。

问题
1) 编译器将 BOOL 'isRunning' 标记为 strong 链接:

在此块中强烈捕获“自我”可能会导致保留 循环。


2) 在尝试添加块操作之前,我检查了队列中是否有任何操作。
但我总是收到以下错误:

-[NSOperationQueue addOperation:]:操作已完成,无法入队

除了所述问题外,此概念验证似乎有效。

问题:
1)当它只是一个缩放器时,为什么编译将 BOOL 'running' 标记为强行?
2) 如果队列中没有找到,为什么我不能通过添加另一个 NSBlockOperation 来重用 NSOperationQueue?

以下为完整代码:

#define START 0
#define STOP 1

@interface ricViewController ()
@property (assign) BOOL running;
@end

@implementation ricViewController {
    NSOperationQueue *operationQueue;
    NSBlockOperation *blockOperation;
    void (^backgroundBlock)(void);
}

@synthesize running = isRunning;

#pragma mark - ViewController methods

- (void)viewDidLoad {
    operationQueue = [NSOperationQueue new];
    [operationQueue setMaxConcurrentOperationCount:1];
    [operationQueue setName:@"RicQueue"];
    [self buildBackgroundBlock];
    blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
    [super viewDidLoad];
}

// -------------------------------------------------------------------------------------------------------------------

- (void)didReceiveMemoryWarning {
    operationQueue = nil;
}

// -------------------------------------------------------------------------------------------------------------------
#pragma mark - Local methods

- (void)buildBackgroundBlock {
    static int k = 0;
    backgroundBlock = ^{
        while (isRunning) {   // 1) *** compiler warning flag: strong link warning ***
            sleep(1);
            if ([NSThread isMainThread]) {
                NSLog(@"{backgroundBlock} *** Main Thread *** ***");
            } else {
                 NSString *myString = [NSString stringWithFormat:@"{backgroundBlock} count = %i", k++];
                 NSLog(myString);
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.dataLabel.text = myString;
                });

            }
        }
    };
}

// -------------------------------------------------------------------------------------------------------------------
#pragma - Action methods

- (IBAction)exitAction:(UIButton *)sender {
    exit(0);
}

// -------------------------------------------------------------------------------------------------------------------

- (IBAction)segmentedAction:(UISegmentedControl *)sender {

    switch (sender.selectedSegmentIndex) {
        case START:
            NSLog(@"START");
            self.running = YES;
            if (operationQueue.operationCount < 1) {
                [operationQueue addOperation:blockOperation]; // 2) *** fatal error on 2nd pass.
            }
            break;
        case STOP:
            NSLog(@"STOP");
            self.running = NO;
            break;
    }
    return;
}

@end

控制台输出:

BackgroundTask[3759:c07] STOP
BackgroundTask[3759:c07] START
BackgroundTask[3759:1303] {backgroundBlock} count = 0
BackgroundTask[3759:1303] {backgroundBlock} count = 1
BackgroundTask[3759:1303] {backgroundBlock} count = 2
BackgroundTask[3759:1303] {backgroundBlock} count = 3
BackgroundTask[3759:1303] {backgroundBlock} count = 4
BackgroundTask[3759:1303] {backgroundBlock} count = 5
BackgroundTask[3759:1303] {backgroundBlock} count = 6
BackgroundTask[3759:1303] {backgroundBlock} count = 7
BackgroundTask[3759:c07] STOP
BackgroundTask[3759:1303] {backgroundBlock} count = 8

【问题讨论】:

    标签: ios objective-c nsoperationqueue cloudkit nsblockoperation


    【解决方案1】:

    我做了进一步的研究,发现
    *我必须重新创建每个“addOperation”*的 NSBlockOperation 对象,因为 NSOperationQueue拒绝 将 SAME NSOperation 对象重新排队。

    因此以下解决方案:

    - (IBAction)segmentedAction:(UISegmentedControl *)sender {
        switch (sender.selectedSegmentIndex) {
            case START:
                NSLog(@"START");
                self.running = YES;
                blockOperation = nil;
                [self buildBackgroundBlock];
                blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
                [operationQueue addOperation:blockOperation];
                break;
            case STOP:
                NSLog(@"STOP");
                self.running = NO;
                break;
        }
    }
    

    ...至于编译器将 BOOL 'isRunning' 与静态 'self' 相关联:

    在此块中强烈捕获“自我”可能会导致重新训练 循环。

    所有对“自我”的引用都应通过薄弱环节。

    - (void)buildBackgroundBlock {
        static int k = 0;
        BOOL myRunning = isRunning;
        __weak ricViewController *weakObject = self;
    
        backgroundBlock = ^{
            while (myRunning) {
                sleep(1);
                if ([NSThread isMainThread]) {
                    NSLog(@"{backgroundBlock} *** Main Thread *** ***");
                } else {
                    NSString *myString = [NSString stringWithFormat:@"{backgroundBlock} count = %i", k++];
                    NSLog(myString);
                    dispatch_async(dispatch_get_main_queue(), ^{
                    weakObject.dataLabel.text = [myString copy];
                    });
                }
            }
        };
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      • 2015-11-23
      • 2014-02-26
      • 2012-04-17
      相关资源
      最近更新 更多