用户访问通讯簿时发生崩溃报告

时间:2013-05-13 03:04:50

标签: ios crash-reports abaddressbook

在我的应用中,Crashlytics用于收集用户的崩溃报告。这是来自用户的一个崩溃报告。它可能取决于用户的联系信息。我无法重建崩溃,因为我不知道他/她的联系人是什么。有没有人对这种情况有所了解?

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

8 SeeYouKee PhoneNumberInputViewController.m line 538-[PhoneNumberInputViewController dofetchContacts:] 的代码是:

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

编辑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];
}

修改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);
}

3 个答案:

答案 0 :(得分:6)

我看到崩溃的帖子是“com.apple.root.default-priority”

ABAddressBook不是线程安全的,所以如果你从两个不同的线程调用它, 它抛出异常并使应用程序崩溃

即使您始终将调用分派给DISPATCH_QUEUE_PRIORITY_DEFAULT,它也可能在两个不同的线程上运行,因为DISPATCH_QUEUE_PRIORITY_DEFAULT不是串行队列。

使用此命令创建分派到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));

请记住将您对地址簿的所有呼叫分派(同步或异步)到此队列。

修改

看起来你在传递给函数ABAddressBookRequestAccessWithCompletion的完成处理程序块中调用了dofetchContacts。务必在主线程上发出此调用!

文档说:

  

在任意队列上调用完成处理程序。如果你的应用程序   在整个应用程序中使用通讯录,您负责   确保将该地址簿的所有使用情况分发给一个人   排队以确保正确的线程安全操作。

答案 1 :(得分:5)

你是否在调用ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering()的不同线程上调用ABAddressBookCreateWithOptions()和/或ABAddressBookRequestAccessWithCompletion()?

请注意Apple的API文档中的以下内容:

  

在任意队列上调用完成处理程序。如果您的应用在整个应用中使用地址簿,则您有责任确保将该地址簿的所有使用情况分发到单个队列,以确保正确的线程安全操作。

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

或者,检查以确保您没有过早地释放从ABAddressBookCreateWithOptions()返回的ABAddressBookRef。请记住,ABAddressBookRequestAccessWithCompletion()是异步的。

答案 2 :(得分:0)

- (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;
}