Pergunta

Estou recebendo endereços de email fora do catálogo de endereços a partir de um projeto de Cocoa Touch e recebendo alguns resultados inesperados em termos de uso de memória. O usuário abre a ABPeoplePicker e se a entrada AB eles tocam tem um único endereço de e-mail ou nenhum endereço de e-mail que utiliza

  • (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) PeoplePicker shouldContinueAfterSelectingPerson: (ABRecordRef) pessoa

e se a entrada tem vários endereços de e-mail que se move sobre a

  • (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) PeoplePicker shouldContinueAfterSelectingPerson: (ABRecordRef) Propriedade pessoa: (ABPropertyID) identificador de propriedade: (ABMultiValueIdentifier) ??identificador {

No caso endereço de e-mail único, toda a memória usada pelo selecionador é liberado após o endereço de email está selecionado. No segundo caso email múltipla, cerca de 300k é mantido e não liberado, e isso aumenta cada vez que uma entrada do livro de multi-endereço de email está escolhido. Eu acredito que eu tenha liberado manualmente tudo o que preciso para nos métodos AB e eu não posso rastrear o que está segurando-se que a memória ou como corrigi-lo, e eu não estou vendo quaisquer outros posts sobre este ser um bug de forma Eu suspeito que eu tenho um erro. Se alguém tiver alguma idéia o que está acontecendo aqui, por favor me avise. Anexei exemplo de código abaixo para aqueles que desejam reproduzir o problema - ele se comporta de forma idêntica no simulador como no dispositivo para que você possa executá-lo no simulador com Activity Monitor para ver o uso de memória. Obrigado por qualquer ajuda!

Ambos AddressBook.framework e AddressBookUI.framework necessidade de ser adicionado a um projeto de executar este código para que ele funcione, e eu estou usando o 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
Foi útil?

Solução

Durante o desenvolvimento do meu iPhone App Correio Serial eu tinha descoberto um vazamento de memória em ABPeoplePickerNavigationController. Tenho pagamento isto como um erro ao Bug Reporter Apple. Feedback de Apple é que o seu é um bug conhecido (o meu relatório de erro é fechada como uma duplicata de ID 6547310).

Outras dicas

Você poderia tentar correr AnalysisTool sobre ele para ver se ele pode detectar qualquer vazamento no código

Uma opção é fazer com que o selecionador de uma propriedade somente leitura da classe e não sintetizá-lo. Em vez disso, criar um método PeoplePicker garantir que apenas um único exemplo do seletor é instanciado. Se isso não funcionar com o seu ciclo de vida visão atual uma opção seria abstrair isso em uma única classe real.

Aqui está um exemplo que usei para o selecionador de imagem (câmera), que tem o mesmo problema de vazamento:

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

Para isso eu coloquei todos os lançamentos na dealloc e didReceiveMemoryWarning (com um cheque nulo para evitar liberando nil). Neste caso, você vai efetivamente limitar a frequência com o seletor de livro de endereços é instanciado. Em muitos lugares, a Apple recomenda o uso de uma implementação singleton para as APIs selecionador de memória intensiva.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top