akyriak
akyriak

Reputation: 33

Huge delay (no error!) only first time after asking for address book permissions

I am getting a huge delay (5-6 seconds) only the first time after asking for permission from user to use his address book. After the first time, the add new contact view controller shows instantly. Anyone knows why this happens ? I am using Xcode 5 or 6 beta on IOS 7.1 and 8 ( same thing happens )

This is how i ask for permissions:

    ABAddressBookRef addressBook = NULL;
    CFErrorRef error = NULL;

    switch (ABAddressBookGetAuthorizationStatus()) {
        case kABAuthorizationStatusAuthorized: {
            addressBook = ABAddressBookCreateWithOptions(NULL, &error);
            [self addToContacts];
            if (addressBook != NULL) CFRelease(addressBook);
            break;
        }
        case kABAuthorizationStatusDenied: {
            //NSLog(@"Access denied to address book");
            NSString *msgString = @"You have denied access to contacts. Please go to settings to enable access, then try again.";
            UIAlertView *returnAl = [[UIAlertView alloc] initWithTitle:@"Unable to save!" message:msgString delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
            [returnAl show];
            [self performSelector:@selector(dismissAlert:) withObject:returnAl afterDelay:3];

            break;
        }
        case kABAuthorizationStatusNotDetermined: {
            addressBook = ABAddressBookCreateWithOptions(NULL, &error);
            ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
                if (granted) {
                    NSLog(@"Access was granted trying to add");
                    [self addToContacts];
                } else {
                    NSLog(@"Access was not granted");
                }
                if (addressBook != NULL) CFRelease(addressBook);
            });
            break;
        }
        case kABAuthorizationStatusRestricted: {
            NSLog(@"access restricted to address book");
            NSString *msgString = @"You have denied access to contacts. Please go to settings to enable access, then try again.";
            UIAlertView *returnAl = [[UIAlertView alloc] initWithTitle:@"Unable to save!" message:msgString delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
            [returnAl show];
            [self performSelector:@selector(dismissAlert:) withObject:returnAl afterDelay:3];
            break;
        }
    }

This is how i initiate the add new contact

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil,nil);
ABRecordRef person = ABPersonCreate();

// Setting basic properties
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFTypeRef)(user[@"name"]) , nil);
ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFTypeRef)(user[@"surName"]), nil);
ABRecordSetValue(person, kABPersonJobTitleProperty, (__bridge CFTypeRef)(user[@"workTitle"]), nil);
//ABRecordSetValue(person, kABPersonDepartmentProperty, @"iPhone development department", nil);
ABRecordSetValue(person, kABPersonOrganizationProperty, (__bridge CFTypeRef)(user[@"company"]), nil);
ABRecordSetValue(person, kABPersonNoteProperty, @"Contact saved by introdU app", nil);
// Adding phone numbers
ABMutableMultiValueRef phoneNumberMultiValue = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phoneNumberMultiValue, (__bridge CFTypeRef)(user[@"mobile"]), (CFStringRef)@"iPhone", NULL);
ABMultiValueAddValueAndLabel(phoneNumberMultiValue, (__bridge CFTypeRef)(user[@"tel"]), (CFStringRef)@"Work", NULL);
//ABMultiValueAddValueAndLabel(phoneNumberMultiValue, @"08701234567", (CFStringRef)@"0870", NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, phoneNumberMultiValue, nil);
if (phoneNumberMultiValue != NULL) { CFRelease(phoneNumberMultiValue); phoneNumberMultiValue = NULL; };

// Adding url
ABMutableMultiValueRef urlMultiValue = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(urlMultiValue, (__bridge CFTypeRef)(user[@"url"]), kABPersonHomePageLabel, NULL);
ABRecordSetValue(person, kABPersonURLProperty, urlMultiValue, nil);
CFRelease(urlMultiValue);

// Adding emails
ABMutableMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(user[@"email"]), (CFStringRef)@"Work", NULL);
//ABMultiValueAddValueAndLabel(emailMultiValue, @"[email protected]", (CFStringRef)@"Work", NULL);
ABRecordSetValue(person, kABPersonEmailProperty, emailMultiValue, nil);
CFRelease(emailMultiValue);

// Adding address
ABMutableMultiValueRef addressMultipleValue = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
[addressDictionary setObject:user[@"address"] forKey:(NSString *)kABPersonAddressStreetKey];
[addressDictionary setObject:user[@"city"] forKey:(NSString *)kABPersonAddressCityKey];
[addressDictionary setObject:user[@"postalCode"] forKey:(NSString *)kABPersonAddressZIPKey];
[addressDictionary setObject:user[@"country"] forKey:(NSString *)kABPersonAddressCountryKey];
//[addressDictionary setObject:@"gb" forKey:(NSString *)kABPersonAddressCountryCodeKey];
ABMultiValueAddValueAndLabel(addressMultipleValue, (__bridge CFTypeRef)(addressDictionary), kABWorkLabel, NULL);
ABRecordSetValue(person, kABPersonAddressProperty, addressMultipleValue, nil);
CFRelease(addressMultipleValue);

ABPersonSetImageData(person, (__bridge CFTypeRef)(profileImageData), nil);
// Adding person to the address book
ABAddressBookAddRecord(addressBook, person, nil);
CFRelease(addressBook);


// Creating view controller for a new contact

ABNewPersonViewController *c = [[ABNewPersonViewController alloc] init];
[c setNewPersonViewDelegate:self];
[c setDisplayedPerson:person];
if (person != NULL) { CFRelease(person); person = NULL; };
[self.navigationController pushViewController:c animated:YES];

Upvotes: 3

Views: 364

Answers (1)

alivingston
alivingston

Reputation: 1440

This is happening because the completion block for ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) is called on an arbitrary queue.

So, the first time you're running this code, you're calling your view controller presentation on an arbitrary queue - every other time you're calling it on your main queue, so it works fine.

All you need to do is dispatch the completion block to the main queue.

ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            if (granted) {
                NSLog(@"Access was granted trying to add");
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self addToContacts];
                });
            } else {
                NSLog(@"Access was not granted");
            }
            if (addressBook != NULL) CFRelease(addressBook);
        });

Upvotes: 4

Related Questions