数据格式化程序暂时不可用,将在“继续”后重试

时间:2010-10-02 00:49:54

标签: iphone memory-management fullcontact

以下是我收到的错误消息:

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上 - 而不是模拟器(在模拟器上,有&lt; 5个联系人)s

4 个答案:

答案 0 :(得分:6)

您没有收到内存警告这一事实并不意味着它没有被发送:内存警告被传送到主运行循环;当你的功能仍在运行时,它们将无法发送。

相反,请考虑查看电话控制台(Xcode-&gt; Organizer-&gt;您的手机 - &gt;控制台,或iPCU中的等效控制台)。如果它说“内存级别至关重要”并且提到杀死你的应用程序,那么你的内存已经耗尽。此外,当你的内存不足时,崩溃记者会在被杀死的进程旁边写一个“低内存”崩溃日志并“抛弃”;你应该在组织者中看到这些。 (自从iOS 4的“多任务处理”以来,抛弃也会发生在后台任务中。)

如果它只是由于大量自动释放的对象,你可以在一定程度上使用显式的自动释放池来缓解它:

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

    ...

    [pool drain]; pool = nil;
}

您的代码也会泄漏retrv

答案 1 :(得分:1)

当您的应用内存不足时,会发生此错误。你应该阅读Apples Memory Management Guide

答案 2 :(得分: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;
}

答案 3 :(得分:0)

首先,您的代码中存在内存泄漏...修复此问题

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

现在这并不意味着它会创建一个新线程,但是os将管理队列,以便主队列不会被阻塞,你将收到内存警告。从那时起,你必须释放记忆,并确保你不要过去。