在我的应用程序中,我从设备中获取联系人列表, 这一切都按计划进行,直到我到达释放线。
应用程序根据需要进行编译,但在运行时它只是停止,指向发布行并告诉绿灯点亮的文本访问不良。
这是我的代码:
在我自己的队列中使用GCD
调用的函数(因为这是我在后台进行的一个重要过程,我不确定是否必须使用@autoreleasepool
我运行了product-> analyze,这里有一些函数我添加了注释。
-(void)getContacts
{
@autoreleasepool {
ABAddressBookRef iPhoneAddressBook = ABAddressBookCreateWithOptions(NULL, NULL);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(iPhoneAddressBook, ^(bool granted, CFErrorRef error)
{
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted)
{
CFErrorRef error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); // indirection
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableArray* EmailArrayPerPerson = [[NSMutableArray alloc]init];//value stored to EMailArrayPerPerson during its initialization is never read
NSMutableArray* PhoneArrayPerPerson = [[NSMutableArray alloc]init];//value stored to PhoneArrayPerPerson during its initialization is never read
for (int i = 0; i < ABAddressBookGetPersonCount(addressBook); i++)//potential leak of an object stored in to contact
{
NSMutableDictionary *ContactsDetails = [NSMutableDictionary dictionary];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
NSString *contact = (__bridge NSString *)(ABRecordCopyCompositeName(ref));
if([contact length] <=0)
continue;
ContactsDetails = [NSMutableDictionary dictionary];
[ContactsDetails setObject:contact forKey:@"CName"];
ABMultiValueRef emails = ABRecordCopyValue(ref, kABPersonEmailProperty);
EmailArrayPerPerson = [[NSMutableArray alloc]init];
NSLog(@"dictionary is:%@",[ContactsDetails objectForKey:@"CName"]);
for (CFIndex j=0; j < ABMultiValueGetCount(emails); j++)
{
NSString* email = (NSString*)CFBridgingRelease(ABMultiValueCopyValueAtIndex(emails, j));
[EmailArrayPerPerson addObject:email];
}
[ContactsDetails setObject:EmailArrayPerPerson forKey:@"CEMails"];//potential leak in emails
ABMultiValueRef multi = ABRecordCopyValue(ref, kABPersonPhoneProperty);
PhoneArrayPerPerson = [[NSMutableArray alloc]init];
for (CFIndex j=0; j < ABMultiValueGetCount(multi); j++)
{
NSString* phone = (NSString*)CFBridgingRelease(ABMultiValueCopyValueAtIndex(multi, j));
[PhoneArrayPerPerson addObject:phone];
}
[ContactsDetails setObject:PhoneArrayPerPerson forKey:@"CPhones"];
[Contacts addObject:ContactsDetails];
CFRelease(ref);//incorect decrement of the reference count of an object that is not owned at this point by the caller.
CFRelease(multi);
}
CFRelease(allPeople);//Potential leak of an object stored in to addressBook
// CFRelease(addressBook);// *strange issue with bad access is here*
}
else
{
CFRelease(iPhoneAddressBook);
return;
}
}
}
我知道这是一个很大的功能,但我认为我必须按原样添加它以使一切都清楚。
我对iOS SDK
很陌生,所以请你能解释一下那里发生的不良访问情况吗?
我不确定,但我认为addressBook
是冗余分配,因为我已经分配iPhoneAddressBook
我不确定。
(我也不确定是否必须发布它(因为我正在使用ARC
,但ARC
不应该为我释放crefs
)。
答案 0 :(得分:2)
主要问题似乎在这里:
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
// ...
CFRelease(ref); // <-- WRONG
CFArrayGetValueAtIndex()
在其名称中没有“创建”或“复制”,因此您
不要“拥有”返回的对象,不得释放它。
有关详细信息,请参阅“适用于Core Foundation的内存管理编程指南”中的"Ownership Policy"。
要解决contact
的潜在泄漏,请替换
NSString *contact = (__bridge NSString *)(ABRecordCopyCompositeName(ref));
通过
NSString *contact = (__bridge_transfer NSString *)(ABRecordCopyCompositeName(ref));
ABRecordCopyCompositeName()
在其名称中有“复制”,因此您拥有了返回的对象。
__brigde_transfer
将所有权“转移”到ARC,以便对象为
contact
超出范围时发布。