【发布时间】:2014-03-26 17:50:56
【问题描述】:
我正在尝试使用完成处理程序从后台线程上的文本文件加载数据,该完成处理程序将在我使用正则表达式处理数据后写出一个 plist。我收到“枚举时集合发生突变”错误,但我不确定为什么在这种情况下会抛出它。我正在使用块和后台线程。所以我假设我犯了一个逻辑错误,但我不明白为什么:
- 可变数组的计数在断点处不一致(发生错误的地方)
- 在某一时刻,该过程确实正确完成(填充了 data.plist 文件)
- 当我在归档之前尝试使用可变数组的副本时,我 收到“尝试插入 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 包含可变数量的对象(每个周期中的对象数量不同,这使我相信我的后台线程尚未完成处理)。
【问题讨论】:
标签: objective-c multithreading nsmutablearray objective-c-blocks grand-central-dispatch