Форматирование данных временно недоступно, повторная попытка после продолжения

Вот сообщение об ошибке, которое я получаю:

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);

Теперь это не обязательно означает, что он создаст новый поток, однако ОС будет управлять очередью так, чтобы основная очередь не блокировалась, и вы получите предупреждение о памяти. С этого момента вы должны освободить память и убедиться, что вы не переходите.

Другие вопросы по тегам