2012-08-10 109 views
1

所以我想了解GCD。我只是將數據追加一個長期運行的操作我下載這樣的後:for dispatch_async/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

您是否嘗試過用'dispatch_async'封裝整個'for(..)'? – Johnnywho 2012-08-10 08:13:08

+0

@Johnnywho是的,這也不起作用。 – Crystal 2012-08-10 18:20:48

回答

1

崩潰是由__block說明符引起的。通常情況下,該塊所使用的周邊範圍內的每個對象變量都會保留該塊的使用期限。這對dispatch_asyncdispatch_after尤其有用,並且意味着只要塊未完成,對象就會有效。這是看不見的塊的真正力量。但是,如果要更改對象指針或原始變量值,則需要使用__block說明符。該說明符以不同的方式處理對象變量,並且不會按塊保留它們,從而允許在塊完成之前解除分配它們。這正是你正在發生的事情。符合要求:

output = [NSFileHandle fileHandleForUpdatingAtPath:tempPath]; 

您正在創建自動釋放的對象,該對象將在不久的將來發布。由於您正在使用dispatch_async這可能發生在塊仍在運行時發生崩潰。

這裏有兩種解決方案:

  • 你可以讓你的局部變量類的實例變量,以擴展該對象的生命週期,

  • 但最簡單的方法是刪除__block因爲你不改變塊內的對象指針,你根本不需要這個指定符。