Crash report when a user accesses the address book

In my application, Crashlytics is used to collect crash reports from users. Here is one user crash report. Perhaps this depends on the contact information of the user. I cannot recreate the crash, because I do not know what is in his / her contacts. Does anyone have an idea about this situation?

com.apple.root.default-priority Crashed 0 CoreFoundation CFStringCreateCopy + 13 1 AppSupport CPSqliteDatabaseCreateWithPath + 36 2 AppSupport CPSqliteDatabaseCreateWithPath + 36 3 AppSupport CPRecordStoreGetDatabase + 16 4 AppSupport _getReaderConnection + 10 5 AppSupport CPRecordStoreProcessQueryWithBindBlock + 22 6 AppSupport CPRecordStoreCopyAllInstancesOfClassWhereWithBindBlock + 98 7 AddressBook ABCCopyArrayOfAllPeopleInSourceWithSortOrdering + 244 8 SeeYouKee PhoneNumberInputViewController.m line 538-[PhoneNumberInputViewController dofetchContacts:] 9 AddressBook __37-[ABTCC accessRequestWithCompletion:]_block_invoke_0 + 26 10 TCC __TCCAccessRequest_block_invoke_038 + 316 11 ... libxpc.dylib _xpc_connection_call_reply + 26 12 libdispatch.dylib _dispatch_root_queue_drain + 278 13 libdispatch.dylib _dispatch_worker_thread2 + 92 14 libsystem_c.dylib _pthread_wqthread + 360 

Code for 8 SeeYouKee PhoneNumberInputViewController.m line 538-[PhoneNumberInputViewController dofetchContacts:] :

 NSArray *contactsInAddressBook = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, nil, kABPersonSortByLastName)); 

EDIT 1

 -(void)dofetchContacts:(ABAddressBookRef)addressBook{ NSMutableArray *contactMutArr = [NSMutableArray array]; NSMutableString *mStrOfContacts = [NSMutableString string]; NSArray *contactsInAddressBook = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, nil, kABPersonSortByLastName)); if (ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatLastNameFirst) { for (id aPerson in contactsInAddressBook) { ABRecordRef person = (__bridge ABRecordRef)(aPerson); ABMultiValueRef phoneMultiValue = ABRecordCopyValue(person, kABPersonPhoneProperty); ABMultiValueRef emailMultiValue = ABRecordCopyValue(person, kABPersonEmailProperty); int countPhone = 0; int countEmail = 0; NSMutableArray *phoneStrArr; NSMutableArray *emailStrArr; if (phoneMultiValue != NULL) { countPhone = ABMultiValueGetCount(phoneMultiValue); } if (emailMultiValue != NULL) { countEmail = ABMultiValueGetCount(emailMultiValue); } if (countEmail>0) { emailStrArr = [NSMutableArray array]; for (int i = 0; i < countEmail; i++) { CFStringRef anEmailCF = ABMultiValueCopyValueAtIndex(emailMultiValue, i); NSString *anEmail = (__bridge NSString *)anEmailCF; [emailStrArr addObject:anEmail]; if (anEmailCF != NULL)CFRelease(anEmailCF); } } if (countPhone > 0) { phoneStrArr = [NSMutableArray array]; for (int i = 0; i < countPhone; i++) { CFStringRef anPhoneCF = ABMultiValueCopyValueAtIndex(phoneMultiValue, i); NSString *anPhone = (__bridge NSString *)anPhoneCF; NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; NSString *anPhonePureNumber = [[anPhone componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""]; [phoneStrArr addObject:anPhonePureNumber]; if (anPhoneCF != NULL)CFRelease(anPhoneCF); } } // if (arrRefOfEmails != NULL)CFRelease(arrRefOfEmails); CFStringRef lastNameMultiValueCF = ABRecordCopyValue(person, kABPersonLastNameProperty); CFStringRef firstNmaeMultiValueCF = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef middleNmaeMultiValueCF = ABRecordCopyValue(person, kABPersonMiddleNameProperty); NSString *lastNameMultiValue = (__bridge NSString *)lastNameMultiValueCF; NSString *firstNmaeMultiValue = (__bridge NSString *)firstNmaeMultiValueCF; NSString *middleNmaeMultiValue = (__bridge NSString *)middleNmaeMultiValueCF; NSString *name = [NSString stringWithFormat:@"%@%@%@",(![lastNameMultiValue length])?@"":lastNameMultiValue, (![middleNmaeMultiValue length])?@"":middleNmaeMultiValue, (![firstNmaeMultiValue length])?@"":firstNmaeMultiValue]; if (lastNameMultiValueCF != NULL)CFRelease(lastNameMultiValueCF); if (firstNmaeMultiValueCF != NULL)CFRelease(firstNmaeMultiValueCF); if (middleNmaeMultiValueCF != NULL)CFRelease(middleNmaeMultiValueCF); CFDataRef anAvatarCF = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail); NSData *anAvatarData = (__bridge NSData *)anAvatarCF; UIImage *anAvatar = [UIImage imageWithData:anAvatarData]; if (anAvatarCF != NULL)CFRelease(anAvatarCF); NSDictionary *aPersonDict = [NSDictionary dictionaryWithObjectsAndKeys:name, @"name", [phoneStrArr componentsJoinedByString:@"; "], @"phoneNumber", [emailStrArr componentsJoinedByString:@"; "], @"email", anAvatar, @"avatar", nil]; [contactMutArr addObject:aPersonDict]; NSLog(@"------phoneStrArr :%@",phoneStrArr); NSString *enPhoneNumber = @""; if (phoneStrArr) { enPhoneNumber = [EncryptWithMD5 encryptWithMD5: [phoneStrArr componentsJoinedByString:@"; "]]; } [mStrOfContacts appendString:enPhoneNumber]; [mStrOfContacts appendString:@", "]; if (phoneMultiValue != NULL)CFRelease(phoneMultiValue); if (emailMultiValue != NULL)CFRelease(emailMultiValue); } }else{ for (id aPerson in contactsInAddressBook) { ABRecordRef person = (__bridge ABRecordRef)(aPerson); ABMultiValueRef phoneMultiValue = ABRecordCopyValue(person, kABPersonPhoneProperty); ABMultiValueRef emailMultiValue = ABRecordCopyValue(person, kABPersonEmailProperty); int countEmail = 0; NSMutableArray *emailStrArr; NSMutableArray *phoneStrArr; if (emailMultiValue != NULL) { countEmail = ABMultiValueGetCount(emailMultiValue); } if (countEmail>0) { emailStrArr = [NSMutableArray array]; for (int i = 0; i < countEmail; i++) { CFStringRef anEmailCF = ABMultiValueCopyValueAtIndex(emailMultiValue, i); NSString *anEmail = (__bridge NSString *)anEmailCF; [emailStrArr addObject:anEmail]; if (anEmailCF != NULL)CFRelease(anEmailCF); } } int count = ABMultiValueGetCount(phoneMultiValue); if (count > 0) { phoneStrArr = [NSMutableArray array]; for (int i = 0; i < count; i++) { CFStringRef anPhoneCF = ABMultiValueCopyValueAtIndex(phoneMultiValue, i); NSString *anPhone = (__bridge NSString *)anPhoneCF; NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; NSString *anPhonePureNumber = [[anPhone componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""]; [phoneStrArr addObject:anPhonePureNumber]; if (anPhoneCF != NULL)CFRelease(anPhoneCF); } } CFStringRef lastNameMultiValueCF = ABRecordCopyValue(person, kABPersonLastNameProperty); CFStringRef firstNmaeMultiValueCF = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef middleNmaeMultiValueCF = ABRecordCopyValue(person, kABPersonMiddleNameProperty); NSString *lastNameMultiValue = (__bridge NSString *)lastNameMultiValueCF; NSString *firstNmaeMultiValue = (__bridge NSString *)firstNmaeMultiValueCF; NSString *middleNmaeMultiValue = (__bridge NSString *)middleNmaeMultiValueCF; NSString *name = [NSString stringWithFormat:@"%@%@%@", (![firstNmaeMultiValue length])?@"":firstNmaeMultiValue, (![middleNmaeMultiValue length])?@"":middleNmaeMultiValue,(![lastNameMultiValue length])?@"":lastNameMultiValue]; if (lastNameMultiValueCF != NULL)CFRelease(lastNameMultiValueCF); if (firstNmaeMultiValueCF != NULL)CFRelease(firstNmaeMultiValueCF); if (middleNmaeMultiValueCF != NULL)CFRelease(middleNmaeMultiValueCF); CFDataRef anAvatarCF = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail); NSData *anAvatarData = (__bridge NSData *)anAvatarCF; UIImage *anAvatar = [UIImage imageWithData:anAvatarData]; if (anAvatarCF != NULL)CFRelease(anAvatarCF); NSDictionary *aPersonDict = [NSDictionary dictionaryWithObjectsAndKeys:name, @"name", [phoneStrArr componentsJoinedByString:@"; "], @"phoneNumber", [emailStrArr componentsJoinedByString:@"; "], @"email", anAvatar, @"avatar", nil]; [contactMutArr addObject:aPersonDict]; NSString *enPhoneNumber = [EncryptWithMD5 encryptWithMD5: [phoneStrArr componentsJoinedByString:@"; "]]; [mStrOfContacts appendString:enPhoneNumber]; [mStrOfContacts appendString:@", "]; if (phoneMultiValue != NULL)CFRelease(phoneMultiValue); if (emailMultiValue != NULL)CFRelease(emailMultiValue); } } self.contactArr = [[NSArray alloc] initWithArray: contactMutArr]; strOfContacts = [NSString stringWithString:mStrOfContacts]; } 

Edit 2

 -(void)beginFetchContacts{ // Request authorization to Address Book ABAddressBookRef addressBookRef = NULL; if (ABAddressBookRequestAccessWithCompletion) { CFErrorRef *aError=nil; addressBookRef = ABAddressBookCreateWithOptions(NULL, aError); if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) { ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { // First time access has been granted, add the contact if (granted) { [self dofetchContacts:addressBookRef]; }else{ // [self alertActionSwitchOnTheContactsAccess]; [self buttonCancelPressed:nil]; } }); } else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) { // The user has previously given access, add the contact [self dofetchContacts:addressBookRef]; } }else{ addressBookRef = ABAddressBookCreate(); [self dofetchContacts:addressBookRef]; } if (addressBookRef != NULL)CFRelease(addressBookRef); } 
+8
ios crash-reports abaddressbook
source share
3 answers

Maybe you are calling ABAddressBookCreateWithOptions () and / or ABAddressBookRequestAccessWithCompletion () in another thread from which you are calling ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering ()?

Check out the following from the Apple API documentation:

The completion handler is called in an arbitrary queue. If your application uses the address book throughout the application, you are responsible for ensuring that all use of this address book is sent in a single queue to ensure proper thread-safe operation.

Source: http://developer.apple.com/library/ios/#documentation/AddressBook/Reference/ABAddressBookRef_iPhoneOS/Reference/reference.html

Also, make sure that you do not prematurely release the ABAddressBookRef that you received from ABAddressBookCreateWithOptions (). Remember that ABAddressBookRequestAccessWithCompletion () is asynchronous.

+5
source share

I see the broken thread is "com.apple.root.default-priority"

ABAddressBook is NOT thread safe, so if you call it from two different threads, it throws an exception and the application crashes .

even if you always send your calls to DISPATCH_QUEUE_PRIORITY_DEFAULT, it can run on two different threads because DISPATCH_QUEUE_PRIORITY_DEFAULT is not a sequential queue.

Use this to create your next queue that dispatches DISPATCH_QUEUE_PRIORITY_DEFAULT:

 dispatch_queue_t abQueue = dispatch_queue_create("myabqueue", DISPATCH_QUEUE_SERIAL); dispatch_set_target_queue(abQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 

Remember to send (synchronize or asynchronously) all your calls to the address book in this queue.

EDIT:

It looks like you are calling dofetchContacts in the completion handler block passed to the ABAddressBookRequestAccessWithCompletion function. Be sure to send this call to the main thread!

The documentation says:

The completion handler is called in an arbitrary queue. If your application uses the address book throughout the application, you are responsible for ensuring that all use of this address book is sent to the same queue to ensure proper thread safe operation.

+6
source share
 - (IBAction)btn_addprofile:(id)sender { // creating the picker ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init]; // place the delegate of the picker to the controll picker.peoplePickerDelegate = self; // showing the picker app.appstart=0; [self presentModalViewController:picker animated:YES]; // releasing [picker release]; } - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { // assigning control back to the main controller [self dismissModalViewControllerAnimated:YES]; } - (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { add_profile_screen *viewcontroller=[[add_profile_screen alloc]initWithNibName:@"add_profile_screen" bundle:nil]; // setting the first name NSString *str_f =(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSString *str_l=(NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty); NSLog(@"%@",str_f); NSLog(@"%@",str_l); if([str_f isEqualToString:@""] || [str_l isEqualToString:@""] || !str_f || !str_l) { if([str_f isEqualToString:@""] || !str_f ) { viewcontroller.strfirstname=[NSString stringWithFormat:@"%@",str_l]; } else { viewcontroller.strfirstname=[NSString stringWithFormat:@"%@ ",str_f]; } } else { viewcontroller.strfirstname=[NSString stringWithFormat:@"%@ %@",str_f,str_l]; } // viewcontroller.strname=[NSString stringWithFormat:@"%@",(NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty)]; ABMutableMultiValueRef multi = ABRecordCopyValue(person, kABPersonEmailProperty); if (ABMultiValueGetCount(multi) > 0) { // collect all emails in array // for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) for (CFIndex i = 0; i <1; i++) { CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i); viewcontroller.strlastname= (NSString *)emailRef; CFRelease(emailRef); } } // setting the number ABMultiValueRef multi1 = ABRecordCopyValue(person, kABPersonPhoneProperty); viewcontroller.strnumber=[NSString stringWithFormat:@"%@",(NSString*)ABMultiValueCopyValueAtIndex(multi1, 0)]; NSLog(@"%@",viewcontroller.strnumber); [self.navigationController pushViewController:viewcontroller animated:YES]; [viewcontroller release]; // remove the controller [self dismissModalViewControllerAnimated:YES]; return NO; } - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { return NO; } 
0
source share

All Articles