简体   繁体   中英

Data Formatters temporarily unavailable, will re-try after a 'continue'

Here is the error message I get:

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

Here is the code that causes this problem:

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

In the View Controller that calls the said class method, I added the following code to see if memory warnings were being sent. They are not!

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    NSLog(@"InviteFriends - memory warning received");
}

Observations: + Found that error occurs at different points in time - sometimes at index 253, other times at 246.. + Only happens on the IPhone - not the simulator (on the simulator, there are < 5 contacts)s

The fact that you haven't received the memory warning doesn't mean that it wasn't sent: Memory warnings are delivered to the main run loop; they will not be delivered while your function is still running.

Instead, consider looking at the phone console (Xcode->Organizer->Your phone->Console, or the equivalent in iPCU). If it says something like "memory level is critical" and mentions killing your app, then you've run out of memory. Additionally, when you run out of memory, the crash reporter writes a "low memory" crash log with "jettisoned" beside the processes that were killed; you should see these in the Organizer. (Since iOS 4's "multitasking", jettisoning also happens to background tasks.)

If it's due solely to the large pile of autoreleased objects, you can mitigate it to some extent with explicit autorelease pools:

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

    ...

    [pool drain]; pool = nil;
}

Your code also leaks ret and rv .

This error occurs when your app is running out of memory. You should read Apples Memory Management Guide .

I discover ABContact also leaks memory,see part of ABContactHelper code below.

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

First thing is that you have memory leaks in your code... Fix that like this

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

Normally autorelease is flushed at certain times decided by the OS however you can create your own pool to make sure that you don't waste resources. So Ideally you will make the call like this

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

Finally so you do all this and you don't have memory leaks but you still get this error. The answer because the memory warning didn't get to you just as @tc. has said. So the simple answer is that the main run loop was clogged. What you can do is maybe do this operation in a separate thread to make sure that the main loop is not clogged... If you are on iOS 4+ you can do this easily by

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

Now this necessarily does not mean that it will create a new thread however the os will manage the queue such that the main queue does not get blocked and you will receive the memory warning. From then on you must release the memory and make sure you dont go over.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM