-
Notifications
You must be signed in to change notification settings - Fork 40
Post Processors
After the data source loads contacts from the data providers, it runs the contacts through any post processors attached to it. The post processors can add, modify, or remove contacts passed through it. Ohana comes with a set of post processors that are useful in many situations, as well as a set of composite post processors that enable logical operations between post processors. If you don't see a post processor for what you're trying to do, it's easy to write your own.
Ohana provides a set of post processors to help you get started. The existing post processors can be found under the PostProcessors directory.
The OHAlphabeticalSortPostProcessor
sorts contacts by either full name, first name, or last name, depending on the sort mode provided at initialization. If the contact does not have any value for the specified sort field, it will be placed at the end.
// Sort contacts by full name
OHAlphabeticalSortPostProcessor *processor = [[OHAlphabeticalSortPostProcessor alloc] initWithSortMode:OHAlphabeticalSortPostProcessorSortModeFullName];
The OHAlphabeticalSortPostProcessor
sorts contacts in ascending order. If you want to have contacts sorted in descending order, simply add an OHReverseOrderPostProcessor
after this one.
The OHPhoneNumberFormattingPostProcessor
formats the phone numbers of the contacts it processes and stores the formatted values in the customProperties
dictionary of each of the phone number contact fields. The formats that should be used can be set at initialization or by modifying the formats
property. The following formats are available:
-
OHPhoneNumberFormatE164
+15551234567 -
OHPhoneNumberFormatInternational
+1 555-123-4567 -
OHPhoneNumberFormatNational
(555) 123-4567 -
OHPhoneNumberFormatRFC3966
tel:+1-555-123-4567
// Format phone numbers in E164 and National formats
OHPhoneNumberFormattingPostProcessor *processor = [[OHPhoneNumberFormattingPostProcessor alloc] initWithFormats:OHPhoneNumberFormatE164|OHPhoneNumberFormatNational];
// Get the E164 format for contactField
id formattedE164 = [contactField.customProperties objectForKey:kOHFormattedPhoneNumberE164];
if (formattedE164 && [formattedE164 isKindOfClass:[NSString class]]) {
NSLog(@"Formatted phone number: %@", formattedE164);
}
The OHRequiredFieldPostProcessor
filters out contacts that do not have a field matching the required field type for which the post processor is initialized.
// Filter out contacts that do not have a phone number
OHRequiredFieldPostProcessor *processor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypePhoneNumber];
This post processor filters out contacts before they are added to the data source. If you want to filter on selection (i.e. to display all contacts but only allows ones with a phone number to be selected), use the OHRequiredFieldSelectionFilter instead.
The OHRequiredPostalAddressPostProcessor
filters out contacts that do not have a postal address.
// Filter out contacts that do not have a postal address
OHRequiredPostalAddressPostProcessor *processor = [[OHRequiredPostalAddressPostProcessor alloc] init];
The OHReverseOrderPostProcessor
reverses the order of the contacts passed into it.
// Reverse the order of contacts
OHReverseOrderPostProcessor *processor = [[OHReverseOrderPostProcessor alloc] init];
The OHSplitOnFieldTypePostProcessor
splits a contact with multiple contact fields of a given type into separate contacts, each with one of the contact fields.
// Split contacts by phone number
OHSplitOnFieldTypePostProcessor *processor = [[OHSplitOnFieldTypePostProcessor alloc] initWithFieldType:OHContactFieldTypePhoneNumber];
The OHStatisticsPostProcessor
generates statistics on the contacts it processes and stores the results in the customProperties
dictionary of each contact. For each of the contacts it generates the following statistics:
- Total number of contact fields
- Number of phone number fields
- Number of email address fields
- Whether or not the contact has a mobile number
// Create the statistics post processor
OHStatisticsPostProcessor *processor = [[OHStatisticsPostProcessor alloc] init];
// Check how many phone number a contact has
NSUInteger numPhoneNumbers = [(NSNumber *)[contact.customProperties objectForKey:kOHStatisticsNumberOfPhoneNumbers] unsignedIntegerValue];
Ohana provides two composite post processors that allow you to perform AND and OR logic on contacts returned from post processors. You can stack composite post processors to get more complicated logical systems.
The OHCompositeAndPostProcessor
performs an AND logic operation on the contacts returned by the post processors it is initialized with.
// Return contacts that have a phone number
OHRequiredFieldPostProcessor *phoneRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypePhoneNumber];
// Return contacts that have an email address
OHRequiredFieldPostProcessor *emailRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypeEmailAddress];
// Return contacts that have both a phone number and email address
OHCompositeAndPostProcessor *processor = [[OHCompositeAndPostProcessor alloc] initWithPostProcessors:[NSOrderedSet orderedSetWithObjects:phoneRequiredProcessor, emailRequiredProcessor, nil]];
The data source performs an AND operation on the results of top level post processors. The OHCompositeAndPostProcessor
should be used only for nesting, not as a top level post processor.
The OHCompositeOrPostProcessor
performs an OR logic operation on the contacts returned by the post processors it is initialized with.
// Return contacts that have a phone number
OHRequiredFieldPostProcessor *phoneRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypePhoneNumber];
// Return contacts that have an email address
OHRequiredFieldPostProcessor *emailRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypeEmailAddress];
// Return contacts that have either a phone number or email address or both
OHCompositeOrPostProcessor *processor = [[OHCompositeOrPostProcessor alloc] initWithPostProcessors:[NSOrderedSet orderedSetWithObjects:phoneRequiredProcessor, emailRequiredProcessor, nil]];
The OHCompositeXorPostProcessor
performs an XOR logic operation on the contacts returned by the post processors it is initialized with.
// Return contacts that have a phone number
OHRequiredFieldPostProcessor *phoneRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypePhoneNumber];
// Return contacts that have an email address
OHRequiredFieldPostProcessor *emailRequiredProcessor = [[OHRequiredFieldPostProcessor alloc] initWithFieldType:OHContactFieldTypeEmailAddress];
// Return contacts that have either a phone number or email address (but not both)
OHCompositeXorPostProcessor *processor = [[OHCompositeXorPostProcessor alloc] initWithPostProcessors:[NSOrderedSet orderedSetWithObjects:phoneRequiredProcessor, emailRequiredProcessor, nil]];
All post processors must conform to the OHContactsPostProcessorProtocol
. A custom post processor will look something like this:
@interface MyCustomPostProcessor : NSObject <OHContactsPostProcessorProtocol>
@end
@implementation MyCustomPostProcessor
// Synthesize the finished signal (required by protocol)
@synthesize onContactsPostProcessorFinishedSignal = _onContactsPostProcessorFinishedSignal;
- (instancetype)init
{
if (self = [super init]) {
// Initialize the finished signal (required by protocol)
_onContactsPostProcessorFinishedSignal = [[OHContactsPostProcessorFinishedSignal alloc] init];
}
return self;
}
#pragma mark - OHContactsPostProcessorProtocol
- (NSOrderedSet<OHContact *> *)processContacts:(NSOrderedSet<OHContact *> *)preProcessedContacts
{
// Initialize a new ordered set to store processed contacts
NSMutableOrderedSet<OHContact *> *processedContacts = [[NSMutableOrderedSet<OHContact *> alloc] init];
// Process contacts in preProcessedContacts and add to processedContacts
// ...
// Fire the finished signal with the processed contacts
_onContactsPostProcessorFinishedSignal.fire(processedContacts, self);
return processedContacts;
}
@end
Post processors can do very simple actions like sorting contacts alphabetically or filtering contacts without a phone number, or perform much more complex actions like filtering contacts that have a postal address within a certain proximity of the user's current location. The possibilities are limitless!