1

だから私はGCDを理解しようとしています。次のようにダウンロードした後にデータを追加するだけの長時間実行オペレーションがあります。

        NSFileManager *fileManager = [NSFileManager defaultManager];
        __block NSFileHandle *output;
        output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath];
        __block NSError *error = nil;
        BOOL success;
        dispatch_queue_t stitchQueue = dispatch_queue_create("com.test", NULL);

for (NSString *packetName in listOfFiles) {
           dispatch_async(stitchQueue, {
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                NSString *packetPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:packetName];

            NSData *packetData = [[NSData alloc] initWithContentsOfFile:packetPath];

            [output seekToEndOfFile];
            [output writeData:packetData];

            [fileManager removeItemAtPath:packetPath error:&error];
            NSLog(@"Removed file after appending data success: %i Error: %@", success, [error localizedDescription]);
            [self updateManifestColumn:@"IsParsed" withValue:YES forFile:packetName inTable:tableName];

            packetData = nil;
            [packetData release];
            [pool release];
            });
        }
        [output closeFile];

//dispatch_async( // データが結合された後、次の長期実行タスクを実行します)

このコードは、dispatch_async 呼び出しを削除すると機能します。私は何か間違ったことをしていますか?dispatch_async で実行すると、1 回の反復を正常に完了してからクラッシュします。NSFileHandle への不正なアクセスでクラッシュします。1回の反復後に解放されたようです。これを修正するために何をする必要があるのか​​ わかりません。ありがとう!

4

1 に答える 1

1

クラッシュは指定子によって引き起こされ__blockます。通常、ブロックが使用している周囲のスコープのすべてのオブジェクト変数は、このブロックの存続期間中保持されます。dispatch_asyncこれは、またはの場合に特に便利でdispatch_after、ブロックが完了しない限りオブジェクトが有効であることを意味します。これが一見すると見えないブロックの真の力です。ただし、オブジェクト ポインタやプリミティブ変数の値を変更する場合は、指定子を使用する必要があり__blockます。この指定子は、オブジェクト変数を異なる方法で扱い、ブロックごとに保持しないため、ブロックが完了する前に割り当てを解除できます。これはまさにあなたに起こっていることです。列をなして:

output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath];

近い将来にリリースされる autoreleased オブジェクトを作成しています。これはdispatch_asyncおそらくブロックがまだ実行されているときに発生するため、クラッシュが発生します。

2 つの解決策があります。

  • このオブジェクトの寿命を延ばすために、ローカル変数をクラスのインスタンス変数にすることができます。

  • __blockただし、ブロック内のオブジェクトのポインターを変更せず、この指定子がまったく必要ないため、最も簡単な方法は削除することです。

于 2012-08-10T22:41:51.823 に答える