Search code examples
iosobjective-caddressbook

Can't seem to find the solution when dealing with ABAddressBookRef


I've a few 'EXC_BAD_ACCESS' in my code, I tried to figure out what is the problem but I still don't know why. Any ideas?

- (void)requestPermissionForContacts {
    NSLog(@"requestPermissionForContacts");
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(duplicateUserContacts:) name:kAccessGrantedNotification object:nil];
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

    if (addressBook != NULL) {
        if (kWeDontHaveAccessToContacts) {
            ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
                if (granted) {
                    NSLog(@"Access granted");
                    [[NSNotificationCenter defaultCenter] postNotificationName:kAccessGrantedNotification object:nil];
                }
            });
        }
        else if (kWeHaveAccessToContacts) {
            [[NSNotificationCenter defaultCenter] postNotificationName:kAccessGrantedNotification object:nil];
        }
    }
}

- (void)duplicateUserContacts:(NSNotification*)notification {
    NSLog(@"duplicateUserContacts");
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

    if (addressBook != NULL && kWeHaveAccessToContacts) {
        // Get all user contacts
        NSArray *allContacts = [self getAllContacts];
        CFArrayRef allContactsRef = (__bridge CFArrayRef)allContacts;

        // Delete old group if exists
        [self deleteOwnGroup];

        // Create Mobile Control 'white list' group
        [self createGroup];

        // Copy contacts to new group
        if (addressBook != NULL && kWeHaveAccessToContacts) {
            for (int i = 0; i < ABAddressBookGetPersonCount(addressBook); i++) {
                ABRecordRef personFromContacts = CFArrayGetValueAtIndex(allContactsRef, i);
                [self addContactToGroup:personFromContacts];
            }
        }
        CFRelease(allContactsRef);
        CFRelease(addressBook);
    }
}

- (ABRecordRef)getGroupReference {
    NSLog(@"getGroupReference");

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

    if (addressBook != NULL && kWeHaveAccessToContacts) {
        CFArrayRef allGroups = ABAddressBookCopyArrayOfAllGroups(addressBook);

        if (allGroups != NULL) {
            for (int i = 0; i < CFArrayGetCount(allGroups); i++) {
                ABRecordRef group = CFArrayGetValueAtIndex(allGroups, i);
                CFStringRef name = ABRecordCopyCompositeName(group);
                NSString *groupName = (__bridge NSString*)name;

                NSLog(@"groupName: %@", groupName);

                if ([groupName isEqualToString:kCallBlockGroupName]) {
                    self.groupCallBlockRef = group;

                    CFRelease(group);
                    CFRelease(name);
                    CFRelease(allGroups);

                    break;
                }
                else {
                    continue;
                }
            }
        }
    }
    //CFRelease(addressBook);
    return self.groupCallBlockRef != NULL ? self.groupCallBlockRef : NULL;
}

- (NSArray*)getAllContacts {
    NSLog(@"getAllContacts");

    __block NSArray *allContacts = [NSArray new];
    __block CFErrorRef *error = NULL;
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);

    if (addressBook != NULL && kWeHaveAccessToContacts) {
        CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
        allContacts = CFBridgingRelease(people);
        self.arrayOfAllContacts = allContacts;

        CFRelease(addressBook);
        //CFRelease(error);
    }
    else {
        NSLog(@"addressBook is NULL");
        allContacts = NULL;
    }

    NSLog(@"Total number of contacts: %i", allContacts.count);
    return allContacts;
}

- (void)deleteContact:(ABRecordRef)person {
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

    if (addressBook != NULL && kWeHaveAccessToContacts) {
        CFErrorRef error = NULL;
        ABAddressBookRemoveRecord(addressBook, person, &error);
        ABAddressBookSave(addressBook, &error);

        CFRelease(addressBook);
        CFRelease(error);
        CFRelease(person);
    }
}

- (void)blockPerson:(ABRecordRef)person {
    BOOL hasContact = [self checkIfContactExists:person];
    if (hasContact) {
        NSLog(@"Contact exists, delete him.");
        [self deleteContact:person];
    }
    else {
        NSLog(@"Contact not exists.");
    }
}

- (BOOL)checkIfContactExists:(ABRecordRef)person {
    __block BOOL answer = NO;
    CFErrorRef *error = NULL;
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);

    if (addressBook != NULL && kWeHaveAccessToContacts) {
        CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);

        for(int i=0; i<ABAddressBookGetPersonCount(addressBook); i++) {
            ABRecordRef personToCompare = CFArrayGetValueAtIndex(people, i);

            if (ABRecordGetRecordID(personToCompare) == ABRecordGetRecordID(person)) {
                answer = YES;

                CFRelease(addressBook);
                CFRelease(people);
                CFRelease(personToCompare);
                CFRelease(person);

                break;
            }
        }
    }
    return answer;
}

- (void)deleteOwnGroup {
    NSLog(@"deleteOwnGroup");

    ABRecordRef group = [self getGroupReference];
    BOOL hasGroup = group != NULL ? YES : NO;

    if (hasGroup) {
        NSLog(@"Group exists, delete group.");
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

        if (addressBook != NULL && kWeHaveAccessToContacts) {
//            CFErrorRef error = NULL;
            ABAddressBookRemoveRecord(addressBook, group, NULL);
            ABAddressBookSave(addressBook, NULL);

            CFRelease(group);
            CFRelease(addressBook);
        }
    }
    else {
        NSLog(@"Group is not exists, no group to delete.");
    }
}

- (void)createGroup {
    NSLog(@"createGroup");

    ABRecordRef group = [self getGroupReference];
    BOOL hasGroup = group != NULL ? YES : NO;

    if (hasGroup) {
        NSLog(@"Group already exists.");
    }
    else {
        NSLog(@"Group is not exists, create group.");
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

        if (addressBook != NULL && kWeHaveAccessToContacts) {
            ABRecordRef newGroup = ABGroupCreate();
            ABRecordSetValue(newGroup, kABGroupNameProperty, (__bridge CFStringRef)kCallBlockGroupName, NULL);
            ABAddressBookAddRecord(addressBook, newGroup, NULL);
            ABAddressBookSave(addressBook, NULL);
            self.groupCallBlockRef = newGroup;

            CFRelease(newGroup);
            CFRelease(addressBook);
            CFRelease(group);
        }
    }
}

- (void)addContactToGroup:(ABRecordRef)person {
    NSLog(@"addContactToGroup");

    ABRecordRef group = [self getGroupReference];
    BOOL hasGroup = group != NULL ? YES : NO;
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
    //ABRecordID recordID = ABRecordGetRecordID(person);

    if (!hasGroup) {
        [self createGroup];
        group = self.groupCallBlockRef;
    }

    CFErrorRef error = NULL;
    BOOL didAdd = ABGroupAddMember(group, person, &error);

    if (!didAdd || error) {
        NSLog(@"Error adding member to group: %@", error);
    }

    error = NULL;
    BOOL didSave = ABAddressBookSave(addressBook, &error);

    if (!didSave || error) {
        NSLog(@"Error saving member to group: %@", error);
    }
    CFRelease(addressBook);
    CFRelease(error);
    CFRelease(group);
    CFRelease(person);
}
  1. Inside 'deleteOwnGroup':

    ABAddressBookRemoveRecord(addressBook, group, NULL); ABAddressBookSave(addressBook, NULL);

  2. Inside 'addContactToGroup':

    BOOL didAdd = ABGroupAddMember(group, person, &error);


Solution

  • I fixed my code and now it works like a charm, My complete code:

    - (id)initAddressBook {
        self = [super init];
        if (self) {
            self.addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
            ABAddressBookRegisterExternalChangeCallback(self.addressBook, addressBookChangeHandler, NULL);
        }
        return self;
    }
    
    - (void)duplicateUserContactsFromAddressBook:(ABAddressBookRef)myAddressBook {
        NSLog(@"duplicateUserContacts");
    
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            // Get all user contacts
            CFArrayRef allContactsRef = [self getAllContactsInAddressBook:myAddressBook];
    
            // Delete old group if exists
            [self deleteGroupWithName:kGroupNameMobileControl fromAddressBook:myAddressBook];
    
            // Create Mobile Control 'white list' group
            self.groupCallBlockRef = [self createGroupWithName:kGroupNameMobileControl fromAddressBook:myAddressBook];
    
            // Copy contacts to new group
            for (int i = 0; i < ABAddressBookGetPersonCount(myAddressBook); i++) {
                ABRecordRef personFromContacts = CFArrayGetValueAtIndex(allContactsRef, i);
                [self addPerson:personFromContacts toGroup:self.groupCallBlockRef fromAddressBook:myAddressBook];
            }
        }
    }
    
    - (void)deleteGroupWithName:(NSString*)groupName fromAddressBook:(ABAddressBookRef)myAddressBook {
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            CFArrayRef allGroups = ABAddressBookCopyArrayOfAllGroups(myAddressBook);
            if (allGroups != NULL) {
                for (int i = 0; i < CFArrayGetCount(allGroups); i++) {
                    ABRecordRef group = CFArrayGetValueAtIndex(allGroups, i);
                    CFStringRef name = ABRecordCopyCompositeName(group);
                    NSString *currentGroupName = (__bridge NSString*)name;
    
                    if ([currentGroupName isEqualToString:groupName]) {
                        [self deleteGroup:group fromAddressBook:myAddressBook];
                    }
                }
            }
        }
    }
    
    - (ABRecordRef)getGroupReference:(ABAddressBookRef)myAddressBook {
        NSLog(@"getGroupReference");
    
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            CFArrayRef allGroups = ABAddressBookCopyArrayOfAllGroups(myAddressBook);
            if (allGroups != NULL) {
                for (int i = 0; i < CFArrayGetCount(allGroups); i++) {
                    ABRecordRef group = CFArrayGetValueAtIndex(allGroups, i);
                    CFStringRef name = ABRecordCopyCompositeName(group);
                    NSString *groupName = (__bridge NSString*)name;
                    NSLog(@"groupName: %@", groupName);
    
                    if ([groupName isEqualToString:kGroupNameMobileControl]) {
                        self.groupCallBlockRef = group;
                        break;
                    }
                    else {
                        continue;
                    }
                }
            }
        }
        return self.groupCallBlockRef != NULL ? self.groupCallBlockRef : NULL;
    }
    
    - (CFArrayRef)getAllContactsInAddressBook:(ABAddressBookRef)myAddressBook {
        NSLog(@"getAllContacts");
    
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(myAddressBook);
            self.arrayOfAllContacts = people;
        }
        else {
            self.arrayOfAllContacts = NULL;
        }
    
        NSLog(@"Total number of contacts: %li", CFArrayGetCount(self.arrayOfAllContacts));
        return self.arrayOfAllContacts;
    }
    
    - (void)deleteContact:(ABRecordRef)person inAddressBook:(ABAddressBookRef)myAddressBook {
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            CFErrorRef error = NULL;
            ABAddressBookRemoveRecord(myAddressBook, person, &error);
            ABAddressBookSave(myAddressBook, &error);
    
            CFRelease(error);
            CFRelease(person);
        }
    }
    
    - (void)blockPerson:(ABRecordRef)person inAddressBook:(ABAddressBookRef)myAddressBook {
        BOOL hasContact = [self checkIfContactExists:person inAddressBook:myAddressBook];
        if (hasContact) {
            NSLog(@"Contact exists, delete him.");
            [self deleteContact:person inAddressBook:myAddressBook];
        }
        else {
            NSLog(@"Contact not exists.");
        }
    }
    
    - (BOOL)checkIfContactExists:(ABRecordRef)person inAddressBook:(ABAddressBookRef)myAddressBook {
        __block BOOL answer = NO;
    
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(myAddressBook);
    
            for(int i=0; i<ABAddressBookGetPersonCount(myAddressBook); i++) {
                ABRecordRef personToCompare = CFArrayGetValueAtIndex(people, i);
    
                if (ABRecordGetRecordID(personToCompare) == ABRecordGetRecordID(person)) {
                    answer = YES;
    
                    CFRelease(people);
                    CFRelease(personToCompare);
                    CFRelease(person);
    
                    break;
                }
            }
        }
        return answer;
    }
    
    - (ABRecordRef)createGroupWithName:(NSString*)groupName fromAddressBook:(ABAddressBookRef)myAddressBook {
        NSLog(@"createGroup");
        ABRecordRef newGroup = ABGroupCreate();
        if (myAddressBook != NULL && kWeHaveAccessToContacts) {
            ABRecordSetValue(newGroup, kABGroupNameProperty, (__bridge CFStringRef)groupName, NULL);
            ABAddressBookAddRecord(myAddressBook, newGroup, NULL);
            ABAddressBookSave(myAddressBook, NULL);
            self.groupCallBlockRef = newGroup;
        }
        return newGroup;
    }
    
    - (void)addPerson:(ABRecordRef)person toGroup:(ABRecordRef)group fromAddressBook:(ABAddressBookRef)myAddressBook {
        NSLog(@"addContactToGroup");
        ABGroupAddMember(group, person, NULL);
        ABAddressBookSave(myAddressBook, NULL);
    }
    
    static void addressBookChangeHandler(ABAddressBookRef addressBook, CFDictionaryRef info, void *context)
    {
        if (context) {
            [(__bridge CallBlockManager*)context handleAddressBookChange:addressBook withInfo:info];
        }
    }
    
    - (void)handleAddressBookChange:(ABAddressBookRef)myAddressBook withInfo:(CFDictionaryRef)info {
        //
    }