Last active
August 29, 2015 14:09
-
-
Save danielt1263/962d77cef0fff5c836fb to your computer and use it in GitHub Desktop.
Easily access a read-only array of all the people in the contacts database for iOS. (Because Apple STILL hasn't made an ABAddressBook class for iOS like they did for MacOS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
extern NSString *addressBookErrorDomain; | |
typedef NS_ENUM(NSInteger, AddressBookError) { | |
AddressBookErrorOK, | |
AddressBookErrorNoAddressBook, | |
AddressBookErrorNoAccess | |
}; | |
extern NSString *AddressBookChangedNotification; | |
@interface AddressBook : NSObject | |
@property (nonatomic, copy, readonly) NSArray *people; | |
+ (void)performAction:(void (^)(AddressBook *addressBook, NSError *error))action; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "AddressBook.h" | |
@import AddressBook; | |
#import "PersonRecord.h" | |
NSString *addressBookErrorDomain = @"com.hanekedesign.addressbookerror"; | |
NSString *AddressBookChangedNotification = @"com.hanekedesign.addressbookchanged"; | |
static void addressBookCallback(ABAddressBookRef addressBookRef, CFDictionaryRef info, void* context) { | |
[[NSNotificationCenter defaultCenter] postNotificationName:AddressBookChangedNotification object:nil]; | |
} | |
static ABAddressBookRef getAddressBookRef() { | |
static ABAddressBookRef addressBookRef; | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
CFErrorRef* error = NULL; | |
addressBookRef = ABAddressBookCreateWithOptions(NULL, error); | |
if (error) { | |
addressBookRef = NULL; | |
} | |
else { | |
ABAddressBookRegisterExternalChangeCallback(addressBookRef, &addressBookCallback, NULL); | |
} | |
}); | |
return addressBookRef; | |
} | |
@interface AddressBook () | |
@property (nonatomic, assign) ABAddressBookRef addressBookRef; | |
@property (nonatomic, assign, readonly) BOOL isValid; | |
@end | |
@implementation AddressBook | |
+ (void)performAction:(void (^)(AddressBook *addressBook, NSError *error))action { | |
AddressBook *addressBook = [[AddressBook alloc] init]; | |
if (addressBook.isValid) { | |
ABAddressBookRequestAccessWithCompletion(addressBook.addressBookRef, ^(bool granted, CFErrorRef error) { | |
if (granted) { | |
action(addressBook, nil); | |
} | |
else { | |
NSError *error = [NSError errorWithDomain:addressBookErrorDomain code:AddressBookErrorNoAccess userInfo:nil]; | |
action(nil, error); | |
} | |
}); | |
} | |
else { | |
NSError *error = [NSError errorWithDomain:addressBookErrorDomain code:AddressBookErrorNoAddressBook userInfo:nil]; | |
action(nil, error); | |
} | |
} | |
- (instancetype)init { | |
self = [super init]; | |
if (self) { | |
self.addressBookRef = getAddressBookRef(); | |
} | |
return self; | |
} | |
- (BOOL)isValid { | |
return self.addressBookRef != NULL; | |
} | |
- (NSArray *)people { | |
NSMutableArray * result = [[NSMutableArray alloc] init]; | |
NSArray *basePeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(self.addressBookRef)); | |
for (int i = 0; i < basePeople.count; ++i) { | |
ABRecordRef record = (__bridge ABRecordRef)(basePeople[i]); | |
PersonRecord *personRecord = [[PersonRecord alloc] init]; | |
personRecord.compositeName = CFBridgingRelease(ABRecordCopyCompositeName(record)) ?: @""; | |
personRecord.organization = CFBridgingRelease(ABRecordCopyValue(record, kABPersonOrganizationProperty)) ?: @""; | |
personRecord.jobTitle = CFBridgingRelease(ABRecordCopyValue(record, kABPersonJobTitleProperty)) ?: @""; | |
personRecord.emails = [self multiValuesFromRecord:record forProperty:kABPersonEmailProperty]; | |
personRecord.phones = [self multiValuesFromRecord:record forProperty:kABPersonPhoneProperty]; | |
[result addObject:personRecord]; | |
} | |
return result; | |
} | |
- (NSArray *)multiValuesFromRecord:(ABRecordRef)record forProperty:(ABPropertyID)property { | |
ABMultiValueRef baseValues = ABRecordCopyValue(record, property); | |
NSMutableArray *values = [[NSMutableArray alloc] initWithCapacity:ABMultiValueGetCount(baseValues)]; | |
for (int i = 0; i < ABMultiValueGetCount(baseValues); ++i) { | |
MultiValue *multiValue = [[MultiValue alloc] init]; | |
multiValue.label = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(baseValues, i)) ?: @""; | |
multiValue.value = CFBridgingRelease(ABMultiValueCopyValueAtIndex(baseValues, i)) ?: @""; | |
[values addObject:multiValue]; | |
} | |
CFRelease(baseValues); | |
return values; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@objc | |
class ExampleUsingTheAddressBookClass { | |
var people: [PersonRecord] = [] | |
init() { | |
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("addressBookChangedNotification:"), name: AddressBookChangedNotification, object: nil) | |
loadPeople() | |
} | |
func addressBookChangedNotification(notification: NSNotification) { | |
loadPeople() | |
} | |
func loadPeople() { | |
AddressBook.performAction { addressBook, error in | |
if let addressBook = addressBook { | |
people = addressBook.people | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface PersonRecord : NSObject | |
@property (nonatomic, copy) NSString *compositeName; | |
@property (nonatomic, copy) NSString *organization; | |
@property (nonatomic, copy) NSString *jobTitle; | |
@property (nonatomic, copy) NSArray *emails; // of MultiValues | |
@property (nonatomic, copy) NSArray *phones; // of MultiValues | |
@end | |
@interface MultiValue : NSObject | |
@property (nonatomic, copy) NSString *label; | |
@property (nonatomic, copy) NSString *value; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "PersonRecord.h" | |
@implementation PersonRecord | |
@end | |
@implementation MultiValue | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment