5

ABAddressBookGetPersonWithRecordID 및 ABPersonSetImageData와 함께 메모리 누수가 발생합니다. 나는 여기에 게시하기 전에 솔루션을 찾고 있었지만 여전히 이해할 수는 없습니다. iPhone 3GS 또는 iPhone 3G와의 접촉이 아주 길어서 실제로 응용 프로그램이 충돌합니다. 다음은 didSelectRowAtIndexPath 메소드의 코드입니다. 나는이 방법들로 샘플 코드를 보았고 내가 무엇을 놓치고 있는지 보지 못했다. 미리 감사드립니다. (실수 죄송합니다 ...)AddressBook 프레임 워크에서 메모리 누수가 발생했습니다.

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

+0

"실제로 응용 프로그램이 충돌합니다 ..."우리는 충돌 정보가 필요합니다. 나쁜 접근입니까? –

+0

exc_bad_access 오류입니다. CFRelease 전에 값이 NULL이 아닌지 확인하겠습니다. – Najaaa

답변

13

첫째 :은 코어 재단 메모리 관리에 읽어. 아직 규칙을 마음으로 알지 못합니다.

둘째 :가 CF 친화적 인 기능은 이름에서 "복사"를 가질 때, 당신은 NULL위한 그것의 결과를 확인해야하며,이 NULL가 아니라면 완료되면 그 결과를 놓습니다. 그래서이 :이 CFRelease(first); 다음에 결코 경우

first = ABRecordCopyValue(person, kABPersonFirstNameProperty); 

메모리 누수가 될 것입니다.

셋째 : 코어 재단 값이 충돌합니다 CFRelease에 전달, NULL 경우 : firstname

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

경우 NULL (그것이 될 수있는 - 단순히 "스미스"라는 이름의 접촉을 상상) 그때 충돌 이됩니다.

+0

exc_bad_access 오류입니다. Core Foundtation Memory Management를 읽고 첫 번째와 마지막으로 CFRelease를 추가했으나 추락하여 추락했습니다. 그러나 일부 콘택트는 성이나 성을 얻지 못했습니다. 따라서 논리적이었습니다 ... Instruments는 ABAddressBookGetPersonWithRecordID로 라인을 지적했지만 아마 그것은 정말로 신뢰할 수 없습니다. – Najaaa

+0

** 항상 ** Get/Copy/Create 호출에 따라 if (...) 테스트를 수행하여 올바른 결과가 있는지 확인하십시오. 이러한 API 중 하나라도 NULL을 반환 할 수 있습니다. –

+0

ABAddressBookGetPersonWithRecordID로 메모리 누수가 발생하지 않았습니다. 감사합니다. ABPersonSetImageData 문제는 내가 지정하지 않은 이미지 형식 (축소판 등)으로 인한 것 같습니다. – Najaaa