Je reçois des adresses e-mail du carnet d'adresses d'un projet Cocoa Touch et obtient des résultats inattendus en termes d'utilisation de la mémoire. L'utilisateur ouvre la ABPeoplePicker et si l'entrée AB, ils touchent a une adresse e-mail unique ou sans adresse e-mail, il utiliseLe mystère d'utilisation de la mémoire du sélecteur de carnet d'adresses dans le projet iPhone 3.0
- (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) Peoplepicker shouldContinueAfterSelectingPerson: (ABRecordRef) personne
et si l'entrée a plusieurs adresses e-mail, il se déplace sur
- (BOOL) peoplePickerNavigationController: (ABPeoplePickerNavigationController *) peoplepicker shouldContinueAfterSelectingPerson: (ABRecordRef) propriété de personne: (ABPropertyID) identificateur de propriété: identifiant (ABMultiValueIdentifier) {
Dans le cas d'adresse e-mail unique, toute la mémoire utilisée par le sélecteur est libéré après l'adresse e-mail est sélectionnée. Dans le deuxième cas de courrier électronique multiple, environ 300 Ko sont conservés et non publiés, et cela augmente chaque fois qu'une entrée de carnet d'adresses à plusieurs adresses e-mail est choisie. Je crois que j'ai libéré manuellement tout ce dont j'ai besoin dans les méthodes AB et je ne peux pas savoir ce qui se passe dans cette mémoire ou comment y remédier, et je ne vois pas d'autres messages à propos de ce bug. Je soupçonne que j'ai une erreur. Si quelqu'un a des idées sur ce qui se passe ici, s'il vous plaît faites le moi savoir. J'ai ci-joint l'exemple de code ci-dessous pour ceux qui souhaitent reproduire le problème - il se comporte de manière identique dans le simulateur comme sur l'appareil afin que vous puissiez l'exécuter dans le simulateur avec Activity Monitor pour voir l'utilisation de la mémoire. Merci pour toute aide!
Les deux AddressBook.framework et AddressBookUI.framework doivent être ajoutés à un projet en cours d'exécution de ce code afin de fonctionner, et je me sers du 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
Modifié légèrement ce qui précède pour indiquer que AnalysisTool a averti qu'il y avait un appel après une version dans le code d'origine. Le problème de mémoire d'origine reste. – Halle
J'ai une solution de contournement pour faire du sélecteur une variable d'instance avec @property et @synthesize etc, ce qui augmente l'encombrement de la mémoire globale, mais entraîne une limite sur la quantité de mémoire captée, peu importe le nombre de fois demandé. Toujours curieux de connaître la raison sous-jacente de la fuite, cependant. – Halle
Plus d'informations: J'ai exécuté Object Allocations, et dans la période où l'empreinte augmente, la grande augmentation d'allocation est une catégorie appelée "GeneralBlock-53248", qui ajoute environ 50k octets au moment où le Carnet d'adresses est appelé puis un autre 50k lorsque la deuxième page du carnet d'adresses est appelée dans le cas de plusieurs adresses e-mail, avec un octet net et un octet global de la même taille (c'est-à-dire qu'il ne libère jamais d'octets). Lorsque je clique sur la flèche de divulgation du résumé, on me montre qu'au moment où les octets ont été ajoutés, libsqlite3.dylib appelle sqlite3_blob_write. – Halle