1

我已经使用以下代码几年了,它一直有效,但在 iOS 6 中它看起来不再有效。如何获取 iOS 6 设备上所有联系人的列表?

ABAddressBookRef myAddressBook = ABAddressBookCreate();
        NSMutableArray *people = (__bridge_transfer NSMutableArray *)ABAddressBookCopyArrayOfAllPeople(myAddressBook);
        CFRelease(myAddressBook);

        // repeat through all contacts in the inital array we loaded
        for(int i=0; i<[people count]; i++)
        {
            NSString *aName;
            NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue((__bridge ABRecordRef)([people objectAtIndex:i]), kABPersonFirstNameProperty);
            NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue((__bridge ABRecordRef)([people objectAtIndex:i]), kABPersonLastNameProperty);

            if (([firstName isEqualToString:@""] || [firstName isEqualToString:@"(null)"] || firstName == nil) &&
                ([lastName isEqualToString:@""] || [lastName isEqualToString:@"(null)"] || lastName == nil))
            {
                // do nothing
            }
            else 
            {
                aName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];

                if ([firstName isEqualToString:@""] || [firstName isEqualToString:@"(null)"] || firstName == nil)
                {
                    aName = [NSString stringWithFormat:@"%@", lastName];
                }

                if ([lastName isEqualToString:@""] || [lastName isEqualToString:@"(null)"] || lastName == nil)
                {
                    aName = [NSString stringWithFormat:@"%@", firstName];
                }

                [self.tableItems addObject:aName];
            }

        }

        [self.tableItems sortUsingSelector:@selector(compare:)];
4

2 回答 2

4

在 ios6 中,您需要请求读取 AddressBook 的权限,否则您将获得 nil。使用这样的东西:

- (BOOL)askContactsPermission {
    __block BOOL ret = NO;
    if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS6

        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        ABAddressBookRef addressBook = ABAddressBookCreate();
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            ret = granted;
            dispatch_semaphore_signal(sema);
        });
        if (addressBook) {
            CFRelease(addressBook);
        }

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        dispatch_release(sema);
    }
    else { // we're on iOS5 or older
        ret = YES;
    }

    return ret;
}

如果此方法返回 NO,运气不好,您将无法访问 AB。我在这里用信号量锁定,因为如果用户不允许 AB,我不想继续使用我的应用程序。还有其他方法,只需检查 API。

于 2012-11-09T21:16:59.470 回答
4

您确实需要向用户征求许可,这将在您这样做时向用户触发提示。这是另一种使用执行块来处理结果的方法,如果您需要从公共代码中查询当前访问状态,它的使用也与版本无关。

我像这样实现访问管理器

AppContactsAccessManager.h

#import <AddressBook/AddressBook.h>

typedef enum
{
    kABAuthStatusNotDetermined = 0,
    kABAuthStatusRestricted,
    kABAuthStatusDenied,
    kABAuthStatusAuthorized,
    kABAuthStatusPending,
}AddressBookAuthStatus;

typedef void (^AddressbookRequestHandler)(ABAddressBookRef addressBookRef, BOOL available);

@interface AppContactsAccessManager : NSObject
{
     AddressBookAuthStatus status;
}
- (void) requestAddressBookWithCompletionHandler:(AddressbookRequestHandler)handler;
- (AddressBookAuthStatus) addressBookAuthLevel;

@end

AppContactsAccessManager.m

@implementation AppContactsAccessManager

- (BOOL) isStatusAvailable:(AddressBookAuthStatus)theStatus
{
    return (theStatus == kABAuthStatusAuthorized || theStatus == kABAuthStatusRestricted);
}

- (void) requestAddressBookWithCompletionHandler:(AddressbookRequestHandler)handler
{
    ABAddressBookRef addressBookRef = NULL;

    if([self isiOS6]){
        addressBookRef = ABAddressBookCreateWithOptions(nil, nil);
        ABAuthorizationStatus curStatus = ABAddressBookGetAuthorizationStatus();
        if(curStatus == kABAuthorizationStatusNotDetermined)
        {
            status = kABAuthStatusPending;
            ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
                status = ABAddressBookGetAuthorizationStatus();
                if(handler != NULL){
                    handler(addressBookRef, [self isStatusAvailable:status]);
                }
            });
        }else
        {
            status = curStatus;
            dispatch_async(dispatch_get_current_queue(), ^{
                if(handler != NULL){
                    handler(addressBookRef, [self isStatusAvailable:status]);
                }
            });
        }
    }else
    {
        addressBookRef = ABAddressBookCreate();
        status = kABAuthStatusAuthorized;
        dispatch_async(dispatch_get_current_queue(), ^{
            if(handler != NULL){
                handler(addressBookRef, [self isStatusAvailable:status]);
            }
            });
        }
}

- (AddressBookAuthStatus) addressBookAuthLevel
{
        return status;
}

@end

用法看起来像:

AppContactsAccessManager* accessMgr = [AppContactsAccessManager new];
[accessMgr requestAddressBookWithCompletionHandler:^(ABAddressBookRef theAddressBookRef, BOOL available) {
    // do your addressbook stuff in here
}];
于 2012-11-09T22:38:08.713 回答