У меня есть объект NSMutableArray, называемый logBuffer, который содержит информацию журнала и выгружает его в файле каждые N строк. Когда это произойдет, я удалить все свои записи, сNSMutableArray removeAllObjects за пределами исключения исключений
[logBuffer removeAllObjects]
Иногда это бросает исключение:
[__NSArrayM removeObjectAtIndex:]: index 7 beyond bounds [0 .. 6]
Я думаю removeAllObjects внутренне перебирает через все объекты в массиве, но я не уверен, как это может выйти за ее пределы. Мое единственное, хотя в том, что есть еще один поток, который манипулирует массивом, когда объекты удаляются, но я совсем не уверен.
Любые мысли?
EDIT: Вот некоторые дополнительный код:
- (void) addToLog:(NSString*)str {
[logBuffer addObject:s];
if ([logBuffer count] >= kBufferSize) {
[self writeLogOnFile];
}
}
- (void) writeLogOnFile {
NSArray *bufferCopy = [NSArray arrayWithArray:logBuffer]; // create a clone, so that logBuffer doesn't change while dumping data and we have a conflict
NSString *multiline = [bufferCopy componentsJoinedByString:@"\r\n"];
multiline = [NSString stringWithFormat:@"%@\n", multiline];
NSData *data = [multiline dataUsingEncoding:NSUTF8StringEncoding];
NSFileHandle *outputFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[outputFileHandle seekToEndOfFile];
[outputFileHandle writeData:data];
[outputFileHandle closeFile];
[logBuffer removeAllObjects]; // This is where the exception is thrown
}
[CrashManager addToLog:] называется десятками классов, не всегда на главном потоке.
Вот трассировка:
"0 AClockworkBrain 0x0008058f -[SWCrashManager backtrace] + 79",
"1 AClockworkBrain 0x0007fab6 uncaughtExceptionHandler + 310",
"2 CoreFoundation 0x041fe318 __handleUncaughtException + 728",
"3 libobjc.A.dylib 0x03c010b9 _ZL15_objc_terminatev + 86",
"4 libc++abi.dylib 0x044c9a65 _ZL19safe_handler_callerPFvvE + 13",
"5 libc++abi.dylib 0x044c9acd __cxa_bad_typeid + 0",
"6 libc++abi.dylib 0x044cabc2 _ZL23__gxx_exception_cleanup19_Unwind_Reason_CodeP17_Unwind_Exception + 0",
"7 libobjc.A.dylib 0x03c00f89 _ZL26_objc_exception_destructorPv + 0",
"8 CoreFoundation 0x041171c4 -[__NSArrayM removeObjectAtIndex:] + 212",
"9 CoreFoundation 0x04153f70 -[NSMutableArray removeAllObjects] + 96",
"10 AClockworkBrain 0x000817c3 -[SWCrashManager writeLogOnFile] + 691",
"11 AClockworkBrain 0x0008141d -[SWCrashManager addToLog:] + 429",
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM removeObjectAtIndex:]: index 7 beyond bounds [0 .. 6]'
EDIT # 2
После прочтения предложения о @synchronize
, я изменил его:
- (void) addToLog:(NSString*)str {
[self performSelectorOnMainThread:@selector(doAddToLog:) withObject:str waitUntilDone:YES];
}
- (void) doAddToLog:(NSString*)str {
// Do the real stuff
}
- (void) writeLogOnFile {
[self performSelectorOnMainThread:@selector(doWriteLogOnFile) withObject:nil waitUntilDone:YES];
}
- (void) doWriteLogOnFile {
// Do the real stuff
}
Я тестировал код для fe w часов, и он не выбрал исключение. Раньше он падал примерно 1-2 раза в час, поэтому я предполагаю, что проблема исправлена. Может кто-нибудь объяснить, как этот подход отличается от предложения @synchronize
?
Кроме того, разумно ли использовать waitUntilDone: ДА или, возможно, НЕТ было бы лучше в этом случае?
«Моя единственная, хотя в том, что есть еще одна нить, которая манипулирует массив в то время как объекты удаляются» - состояние гонки была моя мгновенная подумал. Как вы используете массив? – 2013-04-02 14:45:21
Попробуйте выполнить регистрацию размера массива прямо перед вызовом * removeAllObjects *. Затем в журнале сбоев прочитайте размер массива (в вашем примере, [0..6] дает размер 7). Если размер изменяется, вы, вероятно, редактируете свой массив во время выполнения * removeAllObjects *. – rdurand
Вы можете попробовать итерировать и удалить объекты вручную, возможно, вы найдете что-то. – rdurand