If the question is whether you can add a checkbox to the table view provided by AddressBookUI
framework (such as the ABPeoplePickerNavigationController
), no, you cannot. There are some modest UI modifications that are permissible (in iOS 8, for example, you can control which contacts are enabled and which are not), but adding your own checkbox to the cell is not possible.
You would probably best abandon AddressBookUI
framework altogether, and use the AddressBook
framework to programmatically retrieve the contacts from the address book, at which point you can create your own UI and do whatever you choose (e.g. add a checkmark). It's more work than the AddressBookUI
interface, but you have complete control over the UX.
For example, if you want to retrieve an array of all of the contacts, you can do something like:
- (void)loadContacts {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status != kABAuthorizationStatusAuthorized && status != kABAuthorizationStatusNotDetermined) {
// user previously denied permission; tell user that they have to authorize this in Settings app
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
NSLog(@"ABAddressBookCreateWithOptions failed: %@", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (!granted) {
// tell user that they just denied permission and that they have authorize app if they want this functionality
// note, because this block is called on background queue, don't forget to dispatch any UI update to the main queue
} else {
NSArray *array = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, NULL, kABPersonSortByLastName));
dispatch_async(dispatch_get_main_queue(), ^{
// update your model and UI here, e.g.
self.allContacts = array;
[self.tableView reloadData];
});
}
CFRelease(addressBook);
});
}
And your UITableViewDataSource
could access these ABRecordRef
properties like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"Cell";
ContactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
ABRecordRef person = (__bridge ABRecordRef)self.allContacts[indexPath.row];
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSString *company = CFBridgingRelease(ABRecordCopyValue(person, kABPersonOrganizationProperty));
ABRecordID recordID = ABRecordGetRecordID(person);
cell.nameLabel.text = [NSString stringWithFormat:@"%@, %@", lastName, firstName];
cell.companyLabel.text = company;
cell.selectedSwitch.on = [self.selectedContacts[@(recordID)] boolValue];
return cell;
}
// this is called when user flips `UISwitch` on the `UITableViewCell`
- (IBAction)didValueChange:(UISwitch *)selectedSwitch
{
ContactTableViewCell *cell = (id)selectedSwitch.superview.superview; // I assume switch is in content view of cell
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; // figure out which row that cell is
ABRecordRef person = (__bridge ABRecordRef)self.allContacts[indexPath.row]; // get ABRecordRef for that row of model array
ABRecordID recordID = ABRecordGetRecordID(person); // now get ABRecordID for that row
BOOL oldValue = [self.selectedContacts[@(recordID)] boolValue]; // get the value of the BOOL
self.selectedContacts[@(recordID)] = @(!oldValue); // flip it
}
Above, I'm assuming you have two model objects, one which is an array of the contacts, another is a dictionary of which contacts are "selected", keyed by a NSNumber
representation of the ABRecordID
.
Clearly, you can implement this however you want, but I just wanted to illustrate the idea.