ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
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 { // we're on iOS 5 or older
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];
}
我使用此代码获取所有联系人,但 ABAddressBookGetPersonCount
工作正常,但 ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering
不工作。
最佳答案
几个问题:
您可以简化获取人员数组的过程,例如:
if (accessGranted) { ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook); NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName)); NSUInteger nPeople = [allPeople count]; // do what you want with the array // don't forget to release `source`; because we bridged allPeople, ARC will take care of that CFRelease(source); }
您很可能没有正确捕获打开错误。应该是:
CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if (!addressBook) { NSLog(@"Error opening address book: %@", CFBridgingRelease(error)); return; }
注意,你要避免的是
CFErrorRef *error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
您偶尔会在 Stack Overflow 上看到这种模式,但它是不正确的。这永远不会返回错误对象。
您不应该使用那样的信号量,因为您在等待用户第一次授予权限时会阻塞主线程。如果您在错误的时间这样做,看门狗进程可能会终止您的应用。
相反,采用异步模式,将在用户授予权限后应运行的代码放在
ABAddressBookRequestAccessWithCompletion
调用的完成 block 参数中。但切勿将信号量与此异步权限 API 结合使用。您可能已经知道如何执行此操作,但是例如,要获取人员的姓名,您可以执行以下操作:
for (NSInteger i = 0; i < nPeople; i++) { ABRecordRef person = (__bridge ABRecordRef)allPeople[i]; NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); NSLog(@"%@ %@", firstName, lastName); }
记得通过静态分析器运行代码(shift+command+B,或者 Xcode 的“Analyze” Product"菜单),它非常擅长识别代码中可能困扰地址簿代码的漏洞。
请记住“Create Rule”,即任何时候调用名称中带有
Create
或Copy
的Core Foundation 函数时,您有责任释放对象,调用CFRelease
或使用CFBridgingRelease
(或__bridge_transfer
)将所有权转移给 ARC。
关于ios - ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28230131/