【问题标题】:Memory leaks with AddressBook frameworkAddressBook 框架的内存泄漏
【发布时间】:2011-05-29 11:12:35
【问题描述】:

我的 ABAddressBookGetPersonWithRecordID 和 ABPersonSetImageData 都有一些内存泄漏。在发帖之前我一直在寻找解决方案,但我仍然不明白。如果我用 iPhone 3GS 玩了很长时间,或者用 iPhone 3G 只玩了几个联系人,实际上应用程序会崩溃。这是我在 didSelectRowAtIndexPath 方法中的代码。我已经看到了使用这些方法的示例代码,但我没有看到我缺少什么。先感谢您。 (有错请见谅……)

Contact *myContact = [fetchedResultsController objectAtIndexPath:indexPath];

cancelCreateContact = NO;


ABAddressBookRef ab = ABAddressBookCreate();
int len = ABAddressBookGetPersonCount(ab);
ABRecordID contactID;
ABRecordRef person;
BOOL alreadyExists = NO;
CFStringRef first, last;

for(int i = 1; i < (len + 1); i++)
{
    person = ABAddressBookGetPersonWithRecordID(ab, (ABRecordID)i);

    if(!person){
        len++;
        continue;
    }

    first = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    last = ABRecordCopyValue(person, kABPersonLastNameProperty);

    if ([[(NSString*)first lowercaseString] isEqualToString:[myContact.firstname lowercaseString]] && [[(NSString*)last lowercaseString] isEqualToString:[myContact.lastname lowercaseString]]) {
        alreadyExists = YES;
        contactID = ABRecordGetRecordID(person);
        break;
    }
}

if (alreadyExists) {
    //NSLog(@"already exists");
    ABRecordRef aContactFound = ABAddressBookGetPersonWithRecordID(ab, contactID);

    ABRecordRef aRecord = ABPersonCreate();

    CFErrorRef anError = NULL;

    CFStringRef firstname = ABRecordCopyValue(aContactFound, kABPersonFirstNameProperty);
    ABRecordSetValue(aRecord, kABPersonFirstNameProperty, firstname, &anError);
    CFRelease(firstname);

    CFStringRef lastname = ABRecordCopyValue(aContactFound, kABPersonLastNameProperty);
    ABRecordSetValue(aRecord, kABPersonLastNameProperty, lastname, &anError);
    CFRelease(lastname);

    CFStringRef job = ABRecordCopyValue(aContactFound, kABPersonJobTitleProperty);
    ABRecordSetValue(aRecord, kABPersonJobTitleProperty, job, &anError);
    CFRelease(job);

    ABMultiValueRef instantMessage = ABRecordCopyValue(aContactFound, kABPersonInstantMessageProperty);
    ABRecordSetValue(aRecord, kABPersonInstantMessageProperty, instantMessage, &anError);
    CFRelease(instantMessage);

    ABMultiValueRef phone = ABRecordCopyValue(aContactFound, kABPersonPhoneProperty);
    ABRecordSetValue(aRecord, kABPersonPhoneProperty, phone, &anError);
    CFRelease(phone);

    ABMultiValueRef email = ABRecordCopyValue(aContactFound, kABPersonEmailProperty);
    ABRecordSetValue(aRecord, kABPersonEmailProperty, email, &anError);
    CFRelease(email);

    CFDataRef imageData = ABPersonCopyImageData(aContactFound);
    ABPersonSetImageData(aRecord, imageData, &anError);
    ABAddressBookSave(ab, &anError);
    CFRelease(imageData);

    ABUnknownPersonViewController *ABView = [[ABUnknownPersonViewController alloc] init];
    ABView.unknownPersonViewDelegate = self;
    ABView.displayedPerson = aRecord;
    ABView.allowsAddingToAddressBook = NO;
    ABView.allowsActions = YES;
    ABView.hidesBottomBarWhenPushed = YES;

    [self.navigationController pushViewController:ABView animated:YES];

    [ABView release];

    CFRelease(aRecord);

}else{
    //NSLog(@"doesn't exist");
    //sinon ouvre une fiche pré-remplie

    ABRecordRef aRecord = ABPersonCreate();

    CFErrorRef anError = nil;

    if(![myContact.firstname isEqualToString:@""]) ABRecordSetValue(aRecord, kABPersonFirstNameProperty, myContact.firstname, &anError);

    if(![myContact.lastname isEqualToString:@""]) ABRecordSetValue(aRecord, kABPersonLastNameProperty, myContact.lastname, &anError);

    if(![myContact.email isEqualToString:@""]) {
        ABMultiValueRef ABemail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        ABMultiValueAddValueAndLabel(ABemail, myContact.email, kABWorkLabel, NULL);
        ABRecordSetValue(aRecord, kABPersonEmailProperty, ABemail, &anError);
        CFRelease(ABemail);
    }

    if(![myContact.phone_business isEqualToString:@""] || ![myContact.phone_mobile isEqualToString:@""]){ 
        ABMultiValueRef ABphones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        if(![myContact.phone_business isEqualToString:@""]) ([myContact.phone_business stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 4 || [myContact.phone_business stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 5) ? ABMultiValueAddValueAndLabel(ABphones, [NSString stringWithFormat:@"014443%@", myContact.phone_business], kABPersonPhoneMainLabel, NULL) : ABMultiValueAddValueAndLabel(ABphones, myContact.phone_business, kABPersonPhoneMainLabel, NULL);
        if(![myContact.phone_mobile isEqualToString:@""] && ([myContact.phone_mobile stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 10)) ABMultiValueAddValueAndLabel(ABphones, myContact.phone_mobile, kABPersonPhoneMobileLabel, NULL);
        ABRecordSetValue(aRecord, kABPersonPhoneProperty, ABphones, &anError);
        CFRelease(ABphones);
    }

    if(![myContact.job isEqualToString:@""]) ABRecordSetValue(aRecord, kABPersonJobTitleProperty, myContact.job, &anError);

    if(![myContact.msn isEqualToString:@""] || ![myContact.twitter isEqualToString:@""] || ![myContact.facebook isEqualToString:@""]){  
        ABMultiValueRef ABmessaging = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
        NSMutableDictionary *dMessaging;

        if(![myContact.msn isEqualToString:@""]){
            dMessaging = [[NSMutableDictionary alloc] init];
            [dMessaging setObject:myContact.msn forKey:(NSString *) kABPersonInstantMessageUsernameKey];
            [dMessaging setObject:@"MSN" forKey:(NSString *)kABPersonInstantMessageServiceKey];
            ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABPersonInstantMessageServiceMSN, NULL);
            [dMessaging release];
        }

        if(![myContact.twitter isEqualToString:@""]){
            dMessaging = [[NSMutableDictionary alloc] init];
            [dMessaging setObject:myContact.twitter forKey:(NSString *) kABPersonInstantMessageUsernameKey];
            [dMessaging setObject:@"Twitter" forKey:(NSString *)kABPersonInstantMessageServiceKey];
            ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABOtherLabel, NULL);
            [dMessaging release];
        }

        if(![myContact.facebook isEqualToString:@""]){
            dMessaging = [[NSMutableDictionary alloc] init];
            [dMessaging setObject:myContact.facebook forKey:(NSString *) kABPersonInstantMessageUsernameKey];
            [dMessaging setObject:@"Facebook" forKey:(NSString *)kABPersonInstantMessageServiceKey];
            ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABOtherLabel, NULL);
            [dMessaging release];

        }


        ABRecordSetValue(aRecord, kABPersonInstantMessageProperty, ABmessaging, &anError);
        CFRelease(ABmessaging);
    }

    //pas dans l'XMLToObjectParser parce que ça prenait une plombe...
    NSURL *url = [NSURL URLWithString:myContact.picture_path];
    NSData *data = [NSData dataWithContentsOfURL:url];

    if(!data){
        NSString *picture_path = (![myContact.gender isEqualToString:@""]) ? [NSString stringWithFormat:@"default_%@_head.png", [myContact.gender lowercaseString]] : @"default_m_head.png";

        [myContact setPicture_path:picture_path];
        NSError *error = nil;
        if(![self.managedObjectContext save:&error]){
            NSLog(@"pb lors de l'enregistrement de picture path");
        }

        //NSData *localData = [NSData dataWithContentsOfFile:myContact.picture_path];
        UIImage *image = [UIImage imageNamed:picture_path];
        NSData *localData = UIImagePNGRepresentation(image);   

        CFDataRef cfLocalData = CFDataCreate(NULL, [localData bytes], [localData length]);
        ABPersonSetImageData(aRecord, cfLocalData, &anError);
        ABAddressBookSave(ab, &anError);
        CFRelease(cfLocalData);

    }else {
        UIImage *image = [UIImage imageWithData:data];
        NSString *extension = [(NSArray*)[myContact.picture_path componentsSeparatedByString:@"."] objectAtIndex:1];

        NSData *localData = ([extension isEqualToString:@"png"]) ? UIImagePNGRepresentation(image) : UIImageJPEGRepresentation(image, 1.0f);   

        CFDataRef cfLocalData = CFDataCreate(NULL, [localData bytes], [localData length]);
        ABPersonSetImageData(aRecord, cfLocalData, &anError);
        ABAddressBookSave(ab, &anError);
        CFRelease(cfLocalData);
    }

    if (anError != nil) { NSLog(@"error :: %@", anError); } 



    ABUnknownPersonViewController *ABView = [[ABUnknownPersonViewController alloc] init];
    ABView.unknownPersonViewDelegate = self;
    ABView.displayedPerson = aRecord;
    ABView.allowsAddingToAddressBook = YES;
    ABView.allowsActions = YES;
    ABView.hidesBottomBarWhenPushed = YES;

    [self.navigationController pushViewController:ABView animated:YES];


    [ABView release];

    CFRelease(aRecord);

}
CFRelease(ab);

【问题讨论】:

  • ",实际上应用程序崩溃了..." 我们需要崩溃信息。这是一个不好的访问?
  • 这是一个 exc_bad_access 错误。我将在 CFRelease 之前检查值是否为 NULL

标签: iphone objective-c memory-leaks addressbook abaddressbook


【解决方案1】:

首先:阅读您的 Core Foundation 内存管理。你还不知道规则。

其次:当 CF 友好函数的名称中包含“复制”时,您必须检查其结果是否为 NULL,如果不是 NULL,则在完成时释放该结果。所以这个:

first = ABRecordCopyValue(person, kABPersonFirstNameProperty);

如果后面没有CFRelease(first);,就会变成内存泄漏。

第三:如果核心基础值为NULL,将其传递给CFRelease会崩溃:

CFStringRef firstname = ABRecordCopyValue(aContactFound, kABPersonFirstNameProperty);
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, firstname, &anError);
CFRelease(firstname);

如果firstnameNULL(它可能是——想象一个简单地命名为“Smith”的联系人),那么就会发生崩溃

【讨论】:

  • 这是一个 exc_bad_access 错误。我阅读了Core Foundation Memory Management并为first和last添加了CFRelease,但它崩溃了,所以我删除了,但你是完全正确的,有些联系人没有姓氏或名字,所以这是合乎逻辑的......仪器用ABAddressBookGetPersonWithRecordID指出了这条线但是也许它不是很可靠。我马上改,谢谢
  • 始终使用 if (...) 测试跟踪您的 Get/Copy/Create 调用,以确定是否有有效结果。这些 API 中的任何一个都可以返回 NULL
  • 我没有使用 ABAddressBookGetPersonWithRecordID 的内存泄漏,谢谢。我认为 ABPersonSetImageData 仍然存在的问题是由于我未指定的图像格式(缩略图等)
  • 我也与 ABPersonSetImageData 发生泄漏,我 100% 确定它的那一行,当注释掉时我没有泄漏。很奇怪。
  • 也许您应该通过提问而不是评论别人的问题来寻求有关 Stack Overflow 问题的帮助。 ;)
猜你喜欢
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多