我从Cocoa Touch项目中获取地址簿中的电子邮件地址,并在内存使用方面获得了一些意想不到的结果。用户打开ABPeoplePicker,如果他们触摸的AB条目有一个电子邮件地址或没有使用的电子邮件地址
如果条目有多个电子邮件地址,则会转到
在单个电子邮件地址的情况下,选择电子邮件地址后,将释放选取器使用的所有内存。在第二个多个电子邮件的情况下,大约300k被保留并且没有被释放,并且每次选择多电子邮件地址簿条目时这都会增加。我相信我已经在AB方法中手动发布了我需要的所有内容,但是我无法追踪到内存中的内容或者如何修复它,而且我没有看到任何其他帖子关于这是一个bug所以我怀疑我有错误。如果有人对此有什么想法,请告诉我。我已经为那些希望重现问题的人添加了下面的示例代码 - 它在模拟器中的行为与在设备上的行为完全相同,因此您可以在带有Activity Monitor的模拟器中运行它以查看内存使用情况。谢谢你的帮助!
需要将AddressBook.framework和AddressBookUI.framework添加到运行此代码的项目中才能使其正常运行,我使用的是3.0 SDK:
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
答案 0 :(得分:1)
您可以尝试在其上运行AnalysisTool以查看它是否可以检测到代码中的任何泄漏
答案 1 :(得分:0)
在开发我的iPhone App Serial Mail期间,我在ABPeoplePickerNavigationController中发现了内存泄漏。我已将此作为错误提交给Apple Bug Reporter。来自Apple的反馈是,他是一个已知的错误(我的错误报告作为ID 6547310的副本被关闭)。
答案 2 :(得分:0)
一个选项是使选择器成为类的只读属性,而不是合成它。相反,创建一个peoplePicker方法确保仅实例化选择器的单个实例。如果这不适用于您当前的视图生命周期,则可以选择将其抽象为实际的单例类。
以下是我用于图像选择器(相机)的示例,它具有相同的泄漏问题:
- (UIImagePickerController*)pickerController
{
// pickerController is a readonly property
if( pickerController == nil )
{
pickerController = [[UIImagePickerController alloc] init];
pickerController.allowsImageEditing = NO;
}
return pickerController;
}
为此,我将所有版本放在dealloc和didReceiveMemoryWarning中(使用nil检查以避免释放nil)。在这种情况下,您将有效地限制实例化地址簿选择器的频率。在许多地方,Apple建议对内存密集型选择器API使用单例实现。