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

在调用上述类方法的视图控制器中,我添加了以下代码以查看是否正在发送内存警告。他们不是!

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

观察: + 发现错误发生在不同的时间点 - 有时在索引 253,其他时间在 246 .. + 只发生在 iPhone 上 - 不是模拟器(在模拟器上,有 < 5 个联系人)

4

4 回答 4

6

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

相反,请考虑查看电话控制台(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.

于 2010-10-02T14:16:04.260 回答
1

当您的应用程序内存不足时会发生此错误。您应该阅读Apples 内存管理指南

于 2010-10-02T02:17:57.443 回答
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;
}
于 2010-11-24T02:23:13.287 回答
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);

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

于 2011-12-23T06:15:10.433 回答