9

複数のサブタスクで構成される 1 つの大きなタスクがあります。その大きなタスクの進捗レポートを追加したいと思います。クラスのドキュメントによると、この種のサブタスクの進行状況は、その子 - 親メカニズムを使用して実行できます
NSProgress

簡単にするために、1 つのサブタスクで構成される大きなタスクがあるとします (もちろん、実際にはさらに多くのサブタスクがあります)。だからこれは私がやったことです:

#define kFractionCompletedKeyPath @"fractionCompleted"  

- (void)runBigTask {
    _progress = [NSProgress progressWithTotalUnitCount:100]; // 100 is arbitrary 

    [_progress addObserver:self
                forKeyPath:kFractionCompletedKeyPath
                   options:NSKeyValueObservingOptionNew
                   context:NULL];

    [_progress becomeCurrentWithPendingUnitCount:100]; 
    [self subTask];
    [_progress resignCurrent];
} 

- (void)subTask {
    NSManagedObjectContext *parentContext = self.managedObjectContext; // self is AppDelegate in this example
    NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [bgContext setParentContext:parentContext];

    [bgContext performBlockAndWait:^{
        NSInteger totalUnit = 1000;
        NSInteger completedUnits = 0;
        NSProgress *subProgress = [NSProgress progressWithTotalUnitCount:totalUnit];

        for (int i=0; i < totalUnit; i++) {   

            // run some Core Data related code...  

            completedUnits++;
            subProgress.completedUnitCount = completedUnits;
        }
    }];
}      

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:kFractionCompletedKeyPath]) {
        if ([object isKindOfClass:[NSProgress class]]) {
            NSProgress *progress = (NSProgress *)object;
            NSLog(@"progress… %f", progress.fractionCompleted);
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

ご覧のとおり、サブタスクはバックグラウンド コンテキストを使用して Core Data 関連のコードを実行し、バックグラウンド コンテキストはメイン コンテキストを親コンテキストとして使用します。
これにより、進行状況の「fractionCompleted」プロパティの奇妙な KVO が発生します。

これはプリントです:

progress… 1.000000 // why???
progress… 0.500000 // why?????
progress… 1.000000 // why???????
progress… 0.666650 // why???????????
progress… 0.666990
progress… 0.667320
progress… 0.667660
progress… 0.667990
progress… 0.668320
...  
progress… 1.000000  

ご覧のとおり、印刷は 1.0、0.5、1.0 で始まり、0.66 に進みます ?!
ここからは正常に動作し、予想どおり 1.0 になります。

なぜこれが起こっているのかを理解しようとしましたが、バックグラウンド コンテキストから親コンテキストを削除すると、正常に動作することに気付きました! 0.0 から 1.0 に進みます。

なぜこれが起こっているのですか?どうすればそれを修正できますか?

この問題を示すために、非常に単純なプロジェクトを追加しました(setParentContext: 呼び出しを削除して、それがなくても正常に機能することを確認できます)。

4

2 に答える 2