Skip to content
This repository has been archived by the owner on Dec 3, 2019. It is now read-only.

Data Providers

Nick Entin edited this page Aug 7, 2016 · 1 revision

How Data Providers Work

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.

Data Provider Delegate

Existing Data Providers

OHCNContactsDataProvider

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
}

OHABAddressBookContactsDataProvider

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
}

Using the System Data Providers

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];
            }
        });
    }
}

Creating Your Own Data Provider

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.