所以我试图了解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次迭代后被释放。我不确定我需要做些什么来解决这个问题。谢谢!
答案 0 :(得分:1)
崩溃是由__block
说明符引起的。通常,块内使用的周围范围内的每个对象变量都会在此块的生命周期内保留。这对dispatch_async
或dispatch_after
特别有用,意味着只要块未完成,对象才有效。这是第一眼看不到的块的真正力量。但是,当您想要更改对象指针或原始变量值时,需要使用__block
说明符。此说明符以不同方式处理对象变量,并且不按块保留它们,从而允许在块完成之前取消分配它们。这正是你发生的事情。在线:
output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath];
你正在创建一个将在不久的将来发布的自动释放对象。由于你正在使用dispatch_async
,这可能在块仍在运行时发生,从而造成崩溃。
有两种解决方案:
您可以将局部变量作为类的实例变量,以延长此对象的生命周期,
但最简单的方法是删除__block
,因为你没有更改块内的对象指针,你根本不需要这个说明符。