如何在 iOS 6 中正确使用 ABAddressBookCreateWithOptions 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12083643/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I correctly use ABAddressBookCreateWithOptions method in iOS 6?
提问by codeqi
I am trying to understand the ABAdressBookCreateWithOptions
and ABAddressBookRequestAccessWithCompletion
methods in iOS 6.
我正在尝试了解iOS 6 中的ABAdressBookCreateWithOptions
和ABAddressBookRequestAccessWithCompletion
方法。
The most information i have been able to find is the following, "To request access to contact data, call the ABAddressBookRequestAccessWithCompletion
function after calling the ABAddressBookCreateWithOptions
function."
我能找到的最多信息如下:“要请求访问联系人数据,请在调用该ABAddressBookRequestAccessWithCompletion
函数后调用该ABAddressBookCreateWithOptions
函数。”
I believe together these methods should alert the user to decide whether to allow the application access to contacts, however when I use them I am seeing no prompt.
我相信这些方法应该一起提醒用户决定是否允许应用程序访问联系人,但是当我使用它们时我没有看到提示。
Could someone provide some sample code of how these methods should be called together in a real world example? How do I create (CFDictionary
) options? I have working code using the deprecated ABAddressBookCreate
method, but need to update to iOS 6 to accommodate privacy concerns.
有人可以提供一些示例代码,说明如何在现实世界的示例中一起调用这些方法吗?如何创建 ( CFDictionary
) 选项?我有使用已弃用ABAddressBookCreate
方法的工作代码,但需要更新到 iOS 6 以解决隐私问题。
Thanks in advance to anyone who can shed some light here!
提前感谢任何可以在这里阐明的人!
回答by Engin Kurutepe
Now that the NDA has been lifted, here is my solution for this for the where you need replace a method which returns an Array. (If you'd rather not block while the user is deciding and are ready to potentially rewrite some of your existing code, please look at David's solution below):
现在 NDA 已经解除,这是我的解决方案,您需要替换返回数组的方法。(如果您不想在用户决定时阻止并准备好重写您现有的一些代码,请查看下面 David 的解决方案):
ABAddressBookRef addressBook = ABAddressBookCreate();
__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);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted) {
NSArray *thePeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
// Do whatever you need with thePeople...
}
Hope this helps somebody...
希望这可以帮助某人...
回答by Nik
Most answers I've seen to this question do crazy complicated things with GCD and end up blocking the main thread. It's not necessary!
我在这个问题上看到的大多数答案都用 GCD 做了疯狂的复杂事情,并最终阻塞了主线程。这不是必需的!
Here's the solution I've been using (works on iOS 5 and iOS 6):
这是我一直在使用的解决方案(适用于 iOS 5 和 iOS 6):
- (void)fetchContacts:(void (^)(NSArray *contacts))success failure:(void (^)(NSError *error))failure {
if (ABAddressBookRequestAccessWithCompletion) {
// on iOS 6
CFErrorRef err;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &err);
if (err) {
// handle error
CFRelease(err);
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
// ABAddressBook doesn't gaurantee execution of this block on main thread, but we want our callbacks to be
dispatch_async(dispatch_get_main_queue(), ^{
if (!granted) {
failure((__bridge NSError *)error);
} else {
readAddressBookContacts(addressBook, success);
}
CFRelease(addressBook);
});
});
} else {
// on iOS < 6
ABAddressBookRef addressBook = ABAddressBookCreate();
readAddressBookContacts(addressBook, success);
CFRelease(addressBook);
}
}
static void readAddressBookContacts(ABAddressBookRef addressBook, void (^completion)(NSArray *contacts)) {
// do stuff with addressBook
NSArray *contacts = @[];
completion(contacts);
}
回答by DavidPhillipOster
The other high ranking answer has problems:
另一个排名靠前的答案有问题:
- it unconditionally calls API that don't exist in iOS older than 6, so your program will crash on old devices.
- it blocks the main thread, so your app is unresponsive, and not making progress, during the time the system alert s up.
- 它无条件调用 iOS 6 之前不存在的 API,因此您的程序将在旧设备上崩溃。
- 它会阻塞主线程,因此在系统警报启动期间,您的应用程序没有响应,并且没有取得进展。
Here's my MRC take on it:
这是我对 MRC 的看法:
ABAddressBookRef ab = NULL;
// ABAddressBookCreateWithOptions is iOS 6 and up.
if (&ABAddressBookCreateWithOptions) {
NSError *error = nil;
ab = ABAddressBookCreateWithOptions(NULL, (CFErrorRef *)&error);
#if DEBUG
if (error) { NSLog(@"%@", error); }
#endif
if (error) { CFRelease((CFErrorRef *) error); error = nil; }
}
if (ab == NULL) {
ab = ABAddressBookCreate();
}
if (ab) {
// ABAddressBookRequestAccessWithCompletion is iOS 6 and up.
if (&ABAddressBookRequestAccessWithCompletion) {
ABAddressBookRequestAccessWithCompletion(ab,
^(bool granted, CFErrorRef error) {
if (granted) {
// constructInThread: will CFRelease ab.
[NSThread detachNewThreadSelector:@selector(constructInThread:)
toTarget:self
withObject:ab];
} else {
CFRelease(ab);
// Ignore the error
}
// CFErrorRef should be owned by caller, so don't Release it.
});
} else {
// constructInThread: will CFRelease ab.
[NSThread detachNewThreadSelector:@selector(constructInThread:)
toTarget:self
withObject:ab];
}
}
}
回答by Eli Burke
This is peripherally related to the original question, but I have not seen it mentioned anywhere else, and it took me about two days to figure it out. If you register a callback for address book changes, it MUST be on the main thread.
这与原始问题有外围关系,但我在其他任何地方都没有看到它提到过,我花了大约两天的时间才弄明白。如果您注册地址簿变化的回调,则必须在主线程上。
For example, in this code, only sync_address_book_two() will ever be called:
例如,在此代码中,只会调用 sync_address_book_two() :
ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool granted, CFErrorRef error) {
if (granted) {
ABAddressBookRegisterExternalChangeCallback (_addressBook, sync_address_book_one, NULL);
dispatch_async(dispatch_get_main_queue(), ^{
ABAddressBookRegisterExternalChangeCallback (_addressBook, sync_address_book_two, NULL);
});
}
});