Domanda

Ricevo indirizzi e-mail dalla Rubrica da un progetto Cocoa Touch e sto ottenendo risultati inaspettati in termini di utilizzo della memoria. L'utente apre ABPeoplePicker e se la voce AB che tocca ha un singolo indirizzo e-mail o nessun indirizzo e-mail che utilizza

  • (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) peoplePicker dovrebbeContinuareAfterSelectingPerson: (ABRecordRef) person

e se la voce ha più indirizzi e-mail, passa a

  • (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) peoplePicker shouldContinueAfterSelectingPerson: (ABRecordRef) person property: (ABPropertyID) identificatore della proprietà: (ABMultiValueIdentifier) ??identificatore {

Nel caso di un singolo indirizzo e-mail, tutta la memoria utilizzata dal selettore viene rilasciata dopo aver selezionato l'indirizzo e-mail. Nel secondo caso di posta elettronica multipla, vengono conservati e non rilasciati circa 300k, e questo aumenta ogni volta che si sceglie una voce della Rubrica multi-mail. Credo di aver rilasciato manualmente tutto ciò di cui ho bisogno nei metodi AB e non riesco a rintracciare ciò che sta trattenendo quella memoria o come risolverlo, e non vedo nessun altro post su questo essere un bug quindi Ho il sospetto di avere un errore. Se qualcuno ha qualche idea su cosa sta succedendo qui, per favore fatemi sapere. Di seguito ho allegato un codice di esempio per coloro che desiderano riprodurre il problema: si comporta in modo identico nel simulatore come sul dispositivo, quindi è possibile eseguirlo nel simulatore con Activity Monitor per vedere l'utilizzo della memoria. Grazie per l'assistenza!

Per poter funzionare, sia AddressBook.framework che AddressBookUI.framework devono essere aggiunti a un progetto che esegue questo codice e sto usando l'SDK 3.0:

testViewController.h:

#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
@interface testViewController : UIViewController <ABPeoplePickerNavigationControllerDelegate> {
    UITextView *emailList ;
}

@property (nonatomic, retain) UITextView *emailList ;
@end

testViewController.m:

#import "testViewController.h"

@implementation testViewController

@synthesize emailList;

- (void) showContactPicker:(id)sender {

ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewController:picker animated:YES];
[picker release];
}


- (void) peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
[self dismissModalViewControllerAnimated:YES];
}

- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    BOOL returnState = NO;

    ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);

    if(ABMultiValueGetCount(emails) <= 0) { // the selected contact has no attached email address

        [self dismissModalViewControllerAnimated:YES];
    }

    else if(ABMultiValueGetCount(emails) == 1) { // the selected contact has exactly one email address

        CFStringRef email = ABMultiValueCopyValueAtIndex(emails, 0);
        NSString *emailString = (NSString *) email;
        self.emailList.text = [self.emailList.text stringByAppendingString:[NSString stringWithFormat:@"%@ ", emailString]];
        [emailString release];
        [self dismissModalViewControllerAnimated:YES];
    }

    else { // the selected contact has many email addresses, continue to the alternate method
        returnState =  YES;
    }

    CFRelease(emails);
    return returnState;
}




- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {  

    ABMultiValueRef multiEmails = ABRecordCopyValue(person, kABPersonEmailProperty);
    CFStringRef multiEmail = ABMultiValueCopyValueAtIndex(multiEmails, identifier);
    CFRelease(multiEmails);
    NSString *multiEmailString = (NSString *) multiEmail;
    //CFRelease(multiEmail); //AnalysisTool pointed out that this is a double release since multiEmailString is an alias of multiEmail
    self.emailList.text = [self.emailList.text stringByAppendingString:[NSString stringWithFormat:@"%@ ", multiEmailString]];
    [multiEmailString release];
    [self dismissModalViewControllerAnimated:YES];
    return NO;
}


- (void)viewDidLoad {
     [super viewDidLoad];

        NSArray *openContactsTitle = [[NSArray alloc] initWithObjects:@"Add Addresses", nil];
        UISegmentedControl *openContacts = [[UISegmentedControl alloc] initWithItems:openContactsTitle];
    openContacts.frame = CGRectMake(10,10,105,30);
    [openContacts addTarget:self action:@selector(showContactPicker:) forControlEvents:UIControlEventValueChanged];
    openContacts.segmentedControlStyle = UISegmentedControlStyleBar;
    openContacts.momentary = TRUE;
    [self.view addSubview:openContacts];
    [openContacts release];
    [openContactsTitle release];

    emailList = [[UITextView alloc] initWithFrame:CGRectMake(10,60,200,200)];
    [self.view addSubview:emailList];
    emailList.text = @"";
}


- (void)dealloc {
    [emailList release];
    [super dealloc];
 }

@end
È stato utile?

Soluzione

Durante lo sviluppo della mia app per iPhone Serial Mail avevo scoperto una perdita di memoria in ABPeoplePickerNavigationController. L'ho archiviato come bug per Apple Bug Reporter. Il feedback di Apple è che si tratta di un bug noto (la mia segnalazione di bug è chiusa come duplicato dell'ID 6547310).

Altri suggerimenti

Puoi provare a eseguire AnalysisTool per vedere se è in grado di rilevare eventuali perdite nel codice

Un'opzione è rendere il selettore una proprietà di sola lettura della classe e non sintetizzarla. Invece, crea un metodo peoplePicker assicurati che venga istanziata solo una singola istanza del selettore. Se ciò non funziona con il ciclo di vita della vista corrente, un'opzione sarebbe quella di astrarre ciò in una vera classe singleton.

Ecco un esempio che ho usato per il selettore di immagini (fotocamera) che presenta lo stesso problema di perdita:

- (UIImagePickerController*)pickerController
{
    // pickerController is a readonly property
    if( pickerController == nil )
    {
        pickerController = [[UIImagePickerController alloc] init];
        pickerController.allowsImageEditing = NO;
    }
    return pickerController;
}

Per questo ho inserito tutte le versioni in dealloc e didReceiveMemoryWarning (con un controllo zero per evitare di rilasciare zero). In questo caso limiterai efficacemente la frequenza con cui viene istanziata la selezione della rubrica. In molti punti Apple consiglia di utilizzare un'implementazione singleton per le API di selezione intensiva della memoria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top