Search code examples
iosobjective-cios8addressbook

Crash while fetching the all contacts from addressbook


I am fetching all the contacts from address-book and uploading those to server. But sometime it crashes on ABRecordCopyValue(person,kABPersonCompositeNameFormatFirstNameFirst)

I am not able to find the scenario and the reason of crash. It doesn't crash every time.

+(NSArray *)getAllContacts
{        
    CFErrorRef *error = nil;       
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);        
    __block BOOL accessGranted = NO;
    if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            accessGranted = granted;
            dispatch_semaphore_signal(sema);
        });
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);            
    }
    else { // we're on iOS 5 or older
        accessGranted = YES;
    }

    if (accessGranted) {

#ifdef DEBUG
        NSLog(@"Fetching contact info ----> ");
#endif

        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
        ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
        CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
        CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
        NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];

        for (int i = 0; i < nPeople; i++)
        {
            ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
            NSString *fname;
            CFTypeRef fnameProperty;
            if (person)
            {
                if (ABRecordCopyValue(person, kABPersonCompositeNameFormatFirstNameFirst))
                {
                    fnameProperty = ABRecordCopyValue(person, kABPersonCompositeNameFormatFirstNameFirst);
                    fname = (__bridge NSString*)fnameProperty;
                }
                else
                {
                    fname = @"";
                }

                NSMutableArray *phoneNumbers = [[NSMutableArray alloc] init];

                ABMultiValueRef multiPhones = ABRecordCopyValue(person, kABPersonPhoneProperty);
                for(CFIndex i=0;i<ABMultiValueGetCount(multiPhones);i++)
                {
                    CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(multiPhones, i);
                    NSString *phoneNumber = (__bridge NSString *) phoneNumberRef;
                    [phoneNumbers addObject:phoneNumber];
                    //NSLog(@"All numbers %@", phoneNumbers);

                }

                for (int i = 0; i < [phoneNumbers count]; i++)
                {
                    NSMutableDictionary *dicContacts = [[NSMutableDictionary alloc]init];
                    [dicContacts setValue:fname forKeyPath:@"Name"];
                    [dicContacts setValue:[[NSUserDefaults standardUserDefaults] valueForKey:@"UserID"] forKeyPath:@"UserID"];

                    [dicContacts setValue:[phoneNumbers objectAtIndex:i] forKeyPath:@"Contact"];
                    [dicContacts setValue:@"0" forKeyPath:@"UserContactID"];
                    [dicContacts setValue:@"AddressBook" forKeyPath:@"ContactType"];
                    [dicContacts setValue:[[NSUserDefaults standardUserDefaults] valueForKeyPath:@"UserID"] forKeyPath:@"UserID"];
                    [items addObject:dicContacts];                        
                }                    
            }                
        }
        return items;
    } else {
        #ifdef DEBUG
        NSLog(@"Cannot fetch Contacts :( ");
        #endif
        return NO;            
    }        
}

Solution

  • Try this method:

       + (NSArray *)getContactsFromPhoneBook {
            NSMutableArray *contacts = [NSMutableArray array];
    
            // Request authorization to Address Book
            __block BOOL accessGranted = NO;
    
            ABAddressBookRef addressBook;
            if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
                addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
            }
            else {
                addressBook = ABAddressBookCreate();
            }
            if (addressBook == NULL) {
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                if (![defaults boolForKey:SHOW_AB_ACCESS_ERROR]) {
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                    message:@"Please allow access for working with your contacts in iOS privacy settings"
                                                                   delegate:nil
                                                          cancelButtonTitle:@"OK"
                                                          otherButtonTitles:nil, nil];
                    [alert show];
    
                    [defaults setBool:YES forKey:SHOW_AB_ACCESS_ERROR];
                }
                // Return with empty array
                return contacts;
            }
    
            if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
                dispatch_semaphore_t sema = dispatch_semaphore_create(0);
                ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
                    accessGranted = granted;
                    dispatch_semaphore_signal(sema);
                });
                dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            }
            else { // we're on iOS 5 or older
                accessGranted = YES;
            }
    
            if (accessGranted) {
                CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
                CFIndex count = ABAddressBookGetPersonCount(addressBook);
    
                for (int i = 0; i < count; i++) {
                    NSMutableDictionary *contact = [NSMutableDictionary dictionary];
                    ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
                    ABMultiValueRef phones = ABRecordCopyValue(ref, kABPersonPhoneProperty);
                    NSString *firstName = CFBridgingRelease(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
                    NSString *lastName = CFBridgingRelease(ABRecordCopyValue(ref, kABPersonLastNameProperty));
    
                    if ((ABMultiValueGetCount(phones) > 0) && (firstName || lastName)) {
                        NSArray *phoneNumbersRaw = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(phones));
    
                        NSMutableArray *phoneNumbers = [[NSMutableArray alloc] initWithCapacity:phoneNumbersRaw.count];
    
                        for (NSString *number in phoneNumbersRaw) {
                            //phone number must only contain numbers
                            NSMutableString *strippedNumber = [NSMutableString string];
    
                            NSScanner *scanner = [NSScanner scannerWithString:number];
                            NSCharacterSet *numbers = [NSCharacterSet
                                    characterSetWithCharactersInString:@"0123456789"];
    
                            while (![scanner isAtEnd]) {
                                NSString *buffer;
                                if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
                                    [strippedNumber appendString:buffer];
    
                                } else {
                                    [scanner setScanLocation:([scanner scanLocation] + 1)];
                                }
                            }
                            if (strippedNumber.length >0) {
                                [phoneNumbers addObject:[NSString stringWithString:strippedNumber]];
                            }
                        }
    
                        NSString *email = @"";
                        ABMultiValueRef emails = ABRecordCopyValue(ref, kABPersonEmailProperty);
                        if (ABMultiValueGetCount(emails) > 0) {
                            email = CFBridgingRelease(ABMultiValueCopyValueAtIndex(emails, 0));
                        }
                        [contact setObject:email forKey:@"Email"];
                        CFRelease(emails);
    
                        if (!firstName) {
                            firstName = @"";
                        }
                        [contact setObject:firstName forKey:@"FirstName"];
    
                        if (!lastName) {
                            lastName = @"";
                        }
                        [contact setObject:lastName forKey:@"LastName"];
                        [contact setObject:[NSArray arrayWithArray:phoneNumbers] forKey:@"PhoneNumbers"];
    
                        if (phoneNumbers.count != 0) {
                            [contacts addObject:contact];
                        }
                    }
                    CFRelease(phones);
                    CFRelease(ref);
                }
                CFRelease(allPeople);
            }
            return contacts;
        }