Data Providers
Data providers act as the connection between an initial origin of contacts and the data source. Ohana includes two data providers, used to access system contacts, and provides a protocol for making your own data providers.
At their simplest, data providers must conform to the OHContactsDataProviderProtocol
, but can build off of that. For instance, the system contacts data providers use a delegate protocol to handle authentication.
The OHCNContactsDataProvider
provides access to system contacts using the Contacts framework. This data provider can only be used on devices running iOS 9 or greater (see Using the System Data Providers below). The data provider requires you to provide a delegate conforming to OHCNContactsDataProviderDelegate
to handle system authentication. You can also display any pre-auth notifications at this time.
OHCNContactsDataProvider *dataProvider = [[OHCNContactsDataProvider alloc] initWithDelegate:self];
- (void)dataProviderDidHitAuthenticationChallenge:(OHCNContactsDataProvider *)dataProvider
{
// Ask user for contacts permissions
}
The OHABAddressBookContactsDataProvider
provides access to system contacts using the Address Book framework. This data provider should only be used on pre-iOS 9 devices (see Using the System Data Providers below) since it has many disadvantages from the OHCNContactsDataProvider
. The data provider requires you to provide a delegate conforming to OHABAddressBookContactsDataProviderDelegate
to handle system authentication. You can also display any pre-auth notifications at this time.
OHABAddressBookContactsDataProvider *dataProvider = [[OHABAddressBookContactsDataProvider alloc] initWithDelegate:self];
- (void)dataProviderDidHitAuthenticationChallenge:(OHABAddressBookContactsDataProvider *)dataProvider
{
// Ask user for contacts permissions
}
By combining the built-in data providers, you can support pre-iOS 9 devices while getting the benefits of using the OHCNContactsDataProvider
on iOS 9+ devices. If you are not supporting devices older than iOS 9, you should use the OHCNContactsDataProvider
only.
- (id<OHContactsDataProviderProtocol>)systemDataProvider {
if ([CNContact class]) {
return [[OHCNContactsDataProvider alloc] initWithDelegate:self];
} else {
return [[OHABAddressBookContactsDataProvider alloc] initWithDelegate:self];
}
}
#pragma mark - OHCNContactsDataProviderDelegate, OHABAddressBookContactsDataProviderDelegate
- (void)dataProviderDidHitAuthenticationChallenge:(id<OHContactsDataProviderProtocol>)dataProvider
{
if ([dataProvider isKindOfClass:[OHCNContactsDataProvider class]]) {
CNContactStore *contactStore = [[CNContactStore alloc] init];
[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (granted) {
[dataProvider loadContacts];
}
}];
} else if ([dataProvider isKindOfClass:[OHABAddressBookContactsDataProvider class]]) {
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
if (granted) {
[dataProvider loadContacts];
}
});
}
}
All data providers must conform to the OHContactsDataProviderProtocol
. A custom data provider will look something like this:
@interface MyCustomDataProvider : NSObject <OHContactsDataProviderProtocol>
@end
@implementation MyCustomDataProvider
// Synthesize the properties required by protocol
@synthesize onContactsDataProviderFinishedLoadingSignal = _onContactsDataProviderFinishedLoadingSignal, onContactsDataProviderErrorSignal = _onContactsDataProviderErrorSignal, status = _status, contacts = _contacts;
- (instancetype)init
{
if (self = [super init]) {
_onContactsDataProviderFinishedLoadingSignal = [[OHContactsDataProviderFinishedLoadingSignal alloc] init];
_onContactsDataProviderErrorSignal = [[OHContactsDataProviderErrorSignal alloc] init];
_status = OHContactsDataProviderStatusInitialized;
}
return self;
}
#pragma mark - OHContactsDataProviderProtocol
- (void)loadContacts
{
NSError *error;
// Try to load contacts into self.contacts, or set error if you can't
if (success) {
_status = OHContactsDataProviderStatusLoaded;
self.onContactsDataProviderFinishedLoadingSignal.fire(self);
} else {
_status = OHContactsDataProviderStatusError;
self.onContactsDataProviderErrorSignal.fire(error, self);
}
}
+ (NSString *)providerIdentifier
{
return NSStringFromClass([MyCustomDataProvider class]);
}
@end
Data providers have been provided for the system frameworks, but the potential for data providers is much larger. You can create data providers to load contacts from a local database, social networks, remote server, etc.