0

我試圖從背景線程上的文本文件中加載數據,該數據包含一個完成處理程序,它會在使用常規處理數據後寫出一個plist表達。我收到「集合被枚舉時發生了變化」的錯誤,但我不確定爲什麼它會在這種情況下拋出。我正在使用塊和後臺線程。所以,我認爲我做了一個邏輯錯誤,但我不明白爲什麼:處理後臺線程時出現「收集變異......」的異常情況

  1. 的可變數組的計數是在破發點(發生錯誤)
  2. 不一致在一個點上,過程中沒有完成正確(填充data.plist文件)
  3. 當我試圖在歸檔之前使用可變數組的副本時,I 會收到「試圖插入nil對象」錯誤,但原始nsmutablearray計數在此時似乎有效(看更新)

東西有趣的是,由於不一致的計數和(一次性)成功完成,我認爲我的後臺處理可能是罪魁禍首。

這裏的一個局部的DataManager類的init方法的:

if (!abcMutableArray) 
     abcMutableArray = [[NSMutableArray alloc] init]; 

    NSFileManager *fileManager = [NSFileManager defaultManager]; 

    // If the plist file doesn't exist in the Documents Folder, create it from the text file 
    if (![fileManager fileExistsAtPath:[self filePath]]) { 

     [self createDataFile]; 

    } 

這裏是輔助方法

- (void) createDataFile 
{ 
    __weak DataManager* weakSelf = self; 

    [weakSelf loadData:^(BOOL completed){ 
     if(completed) 
     { 

      //Next line produces **Collection <__NSArrayM: 0x8fa28c0> was mutated while being enumerated** 
      NSData* data = [NSKeyedArchiver archivedDataWithRootObject:[weakSelf abcMutableArray]]; 
      [data writeToFile:[weakSelf filePath] atomically:YES]; 
     } 
    }]; 

} 

此方法執行負載,完成後,通過完成回調給來電者

- (void) loadData:(void (^)(BOOL))completed 
{ 

    __weak DataManager* weakSelf = self; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 

     NSError *localError = NULL; 
     NSStringEncoding fileEncoding = NSUTF8StringEncoding; 
     NSURL* fileURL = [[NSBundle mainBundle] URLForResource:@"data" withExtension:@"txt"]; 
     NSString* fh= [NSString stringWithContentsOfURL:fileURL usedEncoding:&fileEncoding error:&localError]; 

     for (NSString *line in [fh componentsSeparatedByString:@"\n"]) { 

      if (![line hasPrefix:@"#"]) 
      { 
      //  [self parseLine:line]; 

       //parsing routine 
       NSError *error = NULL; 

       Thing* t = [[Thing alloc]init]; 

       NSString* pattern = @"(^.*)\\s(.*)\\s\\[(.*)\\]\\s\\/(.*)\\;\\s(.*)"; 

       NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error]; 

       NSArray *matches = [regEx matchesInString:line 
                options:0 
                range:NSMakeRange(0, [line length])]; 

       for (NSTextCheckingResult *match in matches) { 

        if ([match numberOfRanges] == 6) { 

         //The range at index 0 contains the entire string. 
         thing.a = (NSString*)[line substringWithRange:[match rangeAtIndex:1]]; 

         thing.b = (NSString*)[line substringWithRange:[match rangeAtIndex:2]]; 

         thing.c = (NSString*)[line substringWithRange:[match rangeAtIndex:3]]; 

         thing.d = (NSString*)[line substringWithRange:[match rangeAtIndex:4]]; 

         thing.e = (NSString*)[[[line substringWithRange:[match rangeAtIndex:5]]stringByReplacingOccurrencesOfString:@"/" withString:@". "] stringByReplacingOccurrencesOfString:@".." withString:@"."]; 

         [[weakSelf abcMutableArray] addObject:thing]; 

        } //end-if match 

       } //end-for matches 

      } //end-if line 

     } //end-for lines 

     //file load data process is completed 
     completed(YES); 
    }); 

} 

更新

當試圖複製方法添加到代碼的建議:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:[[weakSelf abcMutableArray]copy]]; 

我在同樣的破發點以下錯誤。

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[12]' 

注比我在NSData的線突破我可以看到abcMutableArray包含可變數量的對象(每個週期中不同的對象,這使我相信,我的後臺線程尚未完成處理)。

回答

2

變化:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:[weakSelf abcMutableArray]]; 

到:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:[[weakSelf abcMutableArray] copy]]; 

這將通過在陣列的拷貝,所以,這將是不可能的變異它。

+0

好建議然而,當重複測試時,這有時會拋出***由於未捕獲的異常'NSInvalidArgumentException',原因:'*** - [__ NSPlaceholderArray initWithObjects:count:]嘗試從對象插入nil對象[ 2443]'|我的測試步驟是執行,請參閱data.plist,刪除data.plist,執行|想知道我的後臺任務有時不完整? –

+0

我最終使用這種方法,我確定我的其他問題與線程相關。 –