在iOS8中获取联系人列表,崩溃应用程序
在iOS8(iPhone 5s)中获取联系人会导致随机崩溃。 崩溃细节:http://hastebin.com/ukihinucaf.md在iOS8中获取联系人列表,崩溃应用程序
在行:
ABMultiValueRef multiEmails = ABRecordCopyValue(person, kABPersonEmailProperty);
这里是全功能:
-(NSArray *) getAllContacts
{
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else {
accessGranted = YES;
}
if (accessGranted) {
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];
for (int i = 0; i < nPeople; i++)
{
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
//get Contact email
ABMultiValueRef multiEmails = ABRecordCopyValue(person, kABPersonEmailProperty);
for (CFIndex j=0; j<ABMultiValueGetCount(multiEmails); j++) {
CFStringRef contactEmailRef = ABMultiValueCopyValueAtIndex(multiEmails, j);
NSString *contactEmail = (__bridge NSString *)contactEmailRef;
[items addObject:contactEmail];
}
}
return items;
} else {
NSLog(@"Cannot fetch Contacts :(");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fetch failed" message:@"Can't fetch your contacts." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
return nil;
}
}
任何人都知道什么是一个问题?
您正在检索ABAddressBookGetPersonCount
(所有来源中的所有人的数量,而不仅仅是默认来源中的人数),并在迭代数组时使用该阈值作为上限。但是该数组并不包含地址簿中的所有人员,而只包含默认数据源中的人员。因此,您可能会超出阵列中的项目数量。
我建议使用CFArrayGetCount
而不是ABAddressBookGetPersonCount
。
你说得对。我已经修复它使用: NSArray * allPeoplearray =(__bridge NSArray *)allPeople; CFIndex nPeople = allPeoplearray.count; 但您的方式更优雅:) – dormitkon 2014-09-26 22:32:05
我刚刚使用了Core Foundation技术,因为您的代码示例使用Core Foundation来遍历数组。但我更喜欢你的方法是好的(尽管我使用'__bridge_transfer'或'CFBridgingRelease',它将所有权转移给ARC,并在数组超出范围时释放数组),然后退出CFArray函数。与电子邮件地址相同,例如'NSString * contactEmail = CFBridgingRelease(ABMultiValueCopyValueAtIndex(multiEmails,j));'。 – Rob 2014-09-27 01:34:41
ABAddressBookCreateWithOptions(NULL,error);
应该是这个
CFErrorRef error = NULL;
ABAddressBookCreateWithOptions(NULL, &error);
这是捕获错误的正确方法。 – Rob 2015-08-12 21:32:57
难道是因为不能够妥善处理内存管理。您不会释放您创建或复制的所有CF对象,并且似乎有许多未被释放的对象。您的应用程序可能因内存警告而不是崩溃而死亡吗? – Sandeep 2014-09-26 22:00:10
崩溃详细信息:EXC_BAD_ACCESS 0x0006000000000068上的KERN_INVALID_ADDRESS对于ABRecordCopyValue方法 – dormitkon 2014-09-26 22:08:03
不是这是造成问题,而是'for'循环都使用变量'i'。总体来说这是有风险的 - 避免这种情况。 – rmaddy 2014-09-26 22:09:21