【问题标题】:For loops with dispatch_async / GCD crash对于具有 dispatch_async / GCD 崩溃的循环
【发布时间】:2012-08-10 00:59:13
【问题描述】:

所以我试图理解 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 次迭代后被释放。我不确定我需要做什么来解决这个问题。谢谢!

【问题讨论】:

  • 你试过用dispatch_async封装整个for(..)吗?
  • @Johnnywho 是的,这也不起作用。

标签: iphone grand-central-dispatch


【解决方案1】:

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

output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath];

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

有两种解决方案:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 2018-02-23
    • 1970-01-01
    相关资源
    最近更新 更多