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 运行它时,它成功完成了一次迭代然后崩溃。它在 NSFileHandle 上的错误访问时崩溃。它似乎在 1 次迭代后被释放。我不确定我需要做什么来解决这个问题。谢谢!

4

1 回答 1

1

崩溃是由__block说明符引起的。通常,该块正在使用的周围范围内的每个对象变量都会在该块的生命周期内保留。这对于dispatch_asyncor尤其有用dispatch_after,并且意味着只要块未完成,对象就会有效。这是第一眼看不到的方块的真正力量。但是,当您要更改对象指针或原始变量值时,您需要使用__block说明符。此说明符以不同方式处理对象变量并且不按块保留它们,因此允许它们在块完成之前被释放。这正是发生在你身上的事情。排队:

output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath];

您正在创建自动发布的对象,该对象将在不久的将来发布。由于您正在使用dispatch_async这可能会在块仍在运行时发生,从而造成崩溃。

有两种解决方案:

  • 您可以使您的局部变量成为类的实例变量,以延长该对象的生命周期,

  • 但最简单的方法是删除__block,因为您不会在块内更改对象的指针,而且您根本不需要这个说明符。

于 2012-08-10T22:41:51.823 回答