2010-10-02 2 views
4

Вот сообщение об ошибке я получаю:данных Форматтеры временно недоступен, будет вновь попробовать после «продолжить»

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

ответ

6

Тот факт, что вы не получили предупреждение о сохранении памяти, не означает, что он не был отправлен. Предупреждения памяти передаются в основной цикл запуска; они не будут доставлены, пока ваша функция все еще работает.

Вместо этого рассмотрите возможность просмотра телефонной консоли (Xcode-> Organizer-> Your phone-> Console или эквивалента в iPCU). Если он говорит что-то вроде «уровень памяти критический» и упоминает об убийстве вашего приложения, тогда у вас закончилась нехватка памяти. Кроме того, когда у вас закончилась нехватка памяти, репортер аварийной ситуации записывает журнал сбоев с «низкой памятью» с «выброшенным» рядом с процессами, которые были убиты; вы должны увидеть их в организаторе. (С «многозадачности» IOS 4 в, отбрасывая также бывает фоновых задач.)

Если это связано исключительно с большой кучей autoreleased объектов, вы можете уменьшить его до некоторой степени с явными пулы autorelease:

for (int i = 0; i< [contacts count] ; i++) { 
    NSAutoreleasePool * pool = [NSAutoreleasePool new]; 

    ... 

    [pool drain]; pool = nil; 
} 

Ваш код также просачивается ret и rv.

+0

Вот и все, спасибо. Я не знал о «Телефонной консоли». И мне еще предстоит узнать об управлении памятью в Obj C. Когда я открыл телефонную консоль и выполнил эту часть кода - сообщения были очень ясными, то есть - предупреждения памяти в изобилии. – amehta

+0

Я должен добавить, однако, что просто добавив NSAutoreleasePool в цикле, предупреждения о памяти или окончательная ошибка не исчезли. Все еще работаю над этим прямо сейчас. – amehta

+0

На догадку вы можете попробовать сделать «[rv addObject: c]» вместо добавления «fullContact». Я не уверен, что ABRecords делает какие-либо кеширования, но если они это сделают, кешированный список номера всех телефонов может быть довольно большим ... –

1

Эта ошибка возникает, когда в вашем приложении заканчивается память. Вы должны прочитать Apples Memory Management Guide.

+1

Я так подумал, поэтому поместил несколько записей в метод didReceiveMemoryWarning для диспетчера представлений, который вызывает этот метод класса. К сожалению, метод предупреждения памяти не вызывается. Поэтому я не уверен. (обновленный вопрос с кодом, который у меня был в контроллере представления) – amehta

+0

didReceiveMemoryWarning никогда не вызывается на симуляторе (поэтому для него есть пункт меню) отлаживает ваше приложение на устройстве. –

+0

эта ошибка не возникает на симуляторе .. только на устройстве..и вот почему я только отлаживаю устройство .. :) – amehta

0

Я обнаружил, что 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; 
} 
0

Первое, что у вас есть утечки памяти в вашем коде ... Fix, что, как это

+(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]; 
} 

Обычно autorelease промывается в определенное время решили операционной системой, однако вы можете создать свой собственный бассейн чтобы вы не тратили ресурсы. Таким образом, В идеале вы будете делать вызов, как этот

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
NSArray *contactArray = [[self contactsWithPhoneNumbers] retain]; 
[pool drain]; 
//This will release the object ownership held by the function 

Наконец, так что вы делаете все это и у вас нет утечки памяти, но вы все равно получите эту ошибку. Ответ, потому что предупреждение памяти не попало к вам так же, как @tc. сказал. Поэтому простой ответ заключается в том, что основной цикл запуска был забит. Что вы можете сделать, это возможно сделать эту операцию в отдельном потоке, чтобы убедиться, что основной цикл не засорен ... Если вы на прошивке 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); 

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