Форматирование данных временно недоступно, повторная попытка после продолжения
Вот сообщение об ошибке, которое я получаю:
ContactsWithPN - start loop
Program received signal: “0”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
Вот код, который вызывает эту проблему:
+(NSArray *) contactsWithPhoneNumbers{
NSArray *contacts = [ABContactsHelper contacts];
NSMutableArray *rv = [[NSMutableArray alloc] init];
NSLog(@"ContactsWithPN - start loop");
for (int i = 0; i< [contacts count] ; i++) {
ABContact * c = (ABContact*)[contacts objectAtIndex:i];
ABContact * fullContact = [ABContact contactWithRecordID:[c recordID]];
if ([[fullContact phoneArray] count] > 0) {
[rv addObject:fullContact];
}
}
NSLog(@"ContactsWithPN - end loop");
NSArray *ret = [[NSArray alloc] initWithArray:rv];
return ret;
}
В View Controller, который вызывает указанный метод класса, я добавил следующий код, чтобы посмотреть, отправляются ли предупреждения памяти. Они не!
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
NSLog(@"InviteFriends - memory warning received");
}
Наблюдения: + Обнаружено, что ошибка возникает в разные моменты времени - иногда в индексе 253, иногда в 246.. + Только на IPhone - не на симуляторе (на симуляторе < 5 контактов)s
4 ответа
Тот факт, что вы не получили предупреждение памяти, не означает, что оно не было отправлено: предупреждения памяти доставляются в основной цикл выполнения; они не будут доставлены, пока ваша функция еще работает.
Вместо этого рассмотрите возможность просмотра консоли телефона (Xcode->Organizer->Your phone->Console или аналогичный в iPCU). Если он говорит что-то вроде "уровень памяти имеет решающее значение" и упоминает об убийстве вашего приложения, значит, у вас недостаточно памяти. Кроме того, когда вы исчерпываете память, аварийный репортер записывает журнал аварийного завершения "мало памяти" с "сброшенным" рядом с процессами, которые были убиты; Вы должны увидеть это в Организаторе. (Так как в iOS 4 "многозадачность", сброс также происходит с фоновыми задачами.)
Если это связано исключительно с большой кучей автоматически выпущенных объектов, вы можете смягчить это до некоторой степени с помощью явных пулов автоматического выпуска:
for (int i = 0; i< [contacts count] ; i++) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
...
[pool drain]; pool = nil;
}
Ваш код также течет ret
а также rv
,
Эта ошибка возникает, когда вашему приложению не хватает памяти. Вы должны прочитать Руководство по управлению памятью яблок.
Я обнаружил, что ABContact также теряет память, см. Часть кода ABContactHelper ниже.
+ (NSArray *) contacts
{
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *thePeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableArray *array = [NSMutableArray arrayWithCapacity:thePeople.count];
for (id person in thePeople)
{
[array addObject:[ABContact contactWithRecord:(ABRecordRef)person]];
}
[thePeople release];
//I think need CFRelease(addressBook); here
return array;
}
Во-первых, у вас есть утечки памяти в вашем коде... Исправьте это так
+(NSArray *) contactsWithPhoneNumbers{
NSArray *contacts = [ABContactsHelper contacts];
NSMutableArray *rv = [[NSMutableArray alloc] init];
NSLog(@"ContactsWithPN - start loop");
for (int i = 0; i< [contacts count] ; i++) {
ABContact * c = (ABContact*)[contacts objectAtIndex:i];
ABContact * fullContact = [ABContact contactWithRecordID:[c recordID]];
if ([[fullContact phoneArray] count] > 0) {
[rv addObject:fullContact];
}
}
NSLog(@"ContactsWithPN - end loop");
NSArray *ret = [[NSArray alloc] initWithArray:rv];
//You need to release rv since you dont need it any more as you have copied the contents to a new array ( this itself is a waste ) so you must release the old array
[rv release];
//Now when you return the array you must still not hold object ownership since the function dies after returning so you give it a delayed release which kicks in when the autorelease is flushed.
return [ret autorelease];
}
Обычно автоматическое освобождение сбрасывается в определенное время по решению ОС, однако вы можете создать свой собственный пул, чтобы не тратить ресурсы. Так что в идеале вы будете звонить так
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *contactArray = [[self contactsWithPhoneNumbers] retain];
[pool drain];
//This will release the object ownership held by the function
Наконец, вы делаете все это, и у вас нет утечек памяти, но вы все равно получаете эту ошибку. Ответ, потому что предупреждение о памяти не дошло до вас как @tc. сказал. Поэтому простой ответ заключается в том, что основной цикл выполнения был засорен. Что вы можете сделать, это, возможно, сделать эту операцию в отдельном потоке, чтобы убедиться, что основной цикл не засорен... Если вы используете iOS 4+, вы можете легко это сделать,
dispatch_queue_t otherQueue = dispatch_queue_create("com.company.otherqueue", NULL);
dispatch_async(otherQueue, ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *contactArray = [[self contactsWithPhoneNumbers] retain];
[pool drain];
}
dispatch_release(otherQueue);
Теперь это не обязательно означает, что он создаст новый поток, однако ОС будет управлять очередью так, чтобы основная очередь не блокировалась, и вы получите предупреждение о памяти. С этого момента вы должны освободить память и убедиться, что вы не переходите.