5

Ich habe einige Speicherverluste mit ABAddressBookGetPersonWithRecordID und ABPersonSetImageData. Ich habe nach Lösungen gesucht, bevor ich hier poste, aber ich verstehe es immer noch nicht. Wenn ich ziemlich lange mit dem iPhone 3GS oder mit nur wenigen Kontakten mit dem iPhone 3G spiele, stürzt die Anwendung eigentlich ab. Hier ist mein Code in der didSelectRowAtIndexPath-Methode. Ich habe Beispielcodes mit diesen Methoden gesehen und ich sehe nicht, was ich vermisse. Vielen Dank im Voraus. (Sorry für Fehler ...)Speicherlecks mit AddressBook Framework

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

", tatsächlich stürzt die Anwendung ab ..." Wir brauchen die Absturzinfo. Ist es ein schlechter Zugang? –

+0

Es ist ein Fehler exc_bad_access. Ich werde überprüfen, dass die Werte nicht NULL sind, bevor CFRelease – Najaaa

Antwort

13

Erstens: lesen Sie auf Ihrem Core Foundation Speicherverwaltung. Sie kennen die Regeln noch nicht auswendig.

Zweitens:, wenn eine CF freundliche Funktion „Kopieren“ im Namen hat, müssen Sie das Ergebnis prüfen NULL, und lassen Sie dieses Ergebnis, wenn Sie fertig, wenn es nicht NULL. So folgt aus:

first = ABRecordCopyValue(person, kABPersonFirstNameProperty); 

Wird ein Speicherleck werden, wenn sie nie von CFRelease(first); gefolgt wird.

Drittens: wenn ein Core Foundation Wert NULL ist, es zu CFRelease abstürzen vorbei:

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

Wenn firstname ist NULL (was es sein könnte - man stelle sich einen Kontakt einfach "Smith" genannt) dann ein Absturz wird passieren.

+0

Es war ein Fehler exc_bad_access. Ich habe die Core Foundation Memory Management gelesen und CFrelease für den ersten und letzten hinzugefügt, aber es ist abgestürzt, also habe ich entfernt, aber Sie haben völlig Recht einige Kontakte nicht Nachname oder Vorname zu bekommen, so war es logisch ... Instrumente zeigte die Linie mit ABAddressBookGetPersonWithRecordID aber vielleicht ist es nicht wirklich zuverlässig. Ich werde es sofort ändern, danke – Najaaa

+0

** Immer ** folgen Sie Ihrem Get/Copy/Create Calls mit einem 'if (...)' Test, um festzustellen, ob es ein gültiges Ergebnis gibt. Jede dieser APIs kann 'NULL' zurückgeben. –

+0

Ich habe keine Speicherlecks mehr mit ABAddressBookGetPersonWithRecordID, danke. Ich denke, das Problem, das ich immer noch mit ABPersonSetImageData habe, ist auf ein Bildformat zurückzuführen, das ich nicht spezifiziere (Vorschaubild, etc). – Najaaa