NSOperationQueue的addOperation:操作完成后无法排队?

时间:2013-05-30 19:54:05

标签: ios objective-c nsoperationqueue cloudkit nsblockoperation

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

方案:
1)根据需要切换后台任务(循环)。
2)后台任务每次迭代通知主线程UI 3)队列中只运行一(1)个块操作。

Modus Operandus
1)使用NSBlockOperation包含背景代码 2)使用区域BOOL切换循环;通过IBAction。

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

  

在这个区块中强烈捕捉'自我'可能会导致保留   周期。


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

  

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

除了陈述的问题之外,这种概念验证似乎是有效的。

问题:
1)当为仅仅是一个缩放器时,为什么编译器将BOOL标记为“运行”为强线?
2)如果在队列中找不到另一个NSBlockOperation,为什么我不能通过添加另一个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

1 个答案:

答案 0 :(得分:4)

我做了进一步的研究,发现 *我必须每次'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];
                });
            }
        }
    };
}