问题描述
我在ABAddressBookGetPersonWithRecordID和ABPersonSetImageData都有一些内存泄漏。在发布之前我一直在寻找解决方案,但我仍然不明白。如果我在iPhone 3GS上玩了很长时间,或者与iPhone 3G只有几个联系人,实际上应用程序崩溃了。这是我在didSelectRowAtIndexPath方法中的代码。我已经看到了使用这些方法的示例代码,我看不到我错过了什么。先感谢您。 (对不起错误......)
I'm having some memory leaks with both ABAddressBookGetPersonWithRecordID and ABPersonSetImageData. I've been looking for solutions before posting here but I still don't understand. If I play quite a long time with the iPhone 3GS or with only a few contacts with iPhone 3G, actually the application crashes. Here is my code in the didSelectRowAtIndexPath method. I've seen sample codes with these methods and I don't see what I'm missing. Thank you in advance. (sorry for mistakes...)
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);
推荐答案
首先:阅读您的Core Foundation内存管理。你还不清楚这些规则。
Firstly: read up on your Core Foundation memory management. You don't yet know the rules by heart.
其次:当一个CF友好的函数在名称中有复制时,你必须检查 NULL
的结果,并在完成时释放该结果,如果它不是 NULL
。所以这个:
Secondly: when a CF-friendly function has "Copy" in the name, you must check its result for NULL
, and release that result when done if it's not NULL
. So this:
first = ABRecordCopyValue(person, kABPersonFirstNameProperty);
如果从未跟随 CFRelease(第一个),将会成为内存泄漏;
。
第三:如果Core Foundation值 NULL
,将其传递给 CFRelease
将崩溃:
Thirdly: if a Core Foundation value is NULL
, passing it to CFRelease
will crash:
CFStringRef firstname = ABRecordCopyValue(aContactFound, kABPersonFirstNameProperty);
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, firstname, &anError);
CFRelease(firstname);
如果 firstname
是 NULL
(可能是 - 想象一个名为Smith的联系人)然后崩溃将发生。
If firstname
is NULL
(which it could be--imagine a contact named simply "Smith") then a crash will happen.
这篇关于内存泄漏与AddressBook框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!