2013-05-13 7 views
8

Nella mia app, Crashlytics viene utilizzato per raccogliere i report sugli arresti anomali degli utenti. Ecco un rapporto di arresto anomalo di un utente. Probabilmente dipende dalle informazioni di contatto dell'utente. Non riesco a ricreare l'incidente, in quanto non so cosa ci sia nei suoi contatti. Qualcuno ha un'idea di questa situazione?Segnalazione di un crash quando l'utente accede alla rubrica

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 

Il codice per 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:@""] 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])[email protected]"":lastNameMultiValue, (![middleNmaeMultiValue length])[email protected]"":middleNmaeMultiValue, (![firstNmaeMultiValue length])[email protected]"":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:@""] 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])[email protected]"":firstNmaeMultiValue, (![middleNmaeMultiValue length])[email protected]"":middleNmaeMultiValue,(![lastNameMultiValue length])[email protected]"":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); 
} 
+0

Se possibile, si prega di fornire il modulo del codice sorgente in cui si stanno recuperando i contatti dalla rubrica? Pochi giorni fa anche io mi sono trovato in un incidente e si è scoperto che si trattava della versione errata dell'oggetto Core Foundation. –

+0

@Deepesh Si prega di verificare l'aggiornamento. –

+0

@Deepesh Ho pensato di aver capito il motivo. È su ABPersonGetCompositeNameFormat. –

risposta

5

potrebbe essere che si sta chiamando ABAddressBookCreateWithOptions() e/o ABAddressBookRequestAccessWithCompletion() in un thread diverso da quello in cui si sta chiamando ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering()?

Si prega di notare quanto segue dalla documentazione delle API di Apple:

Il gestore di completamento viene chiamato su una coda arbitraria. Se la tua app utilizza una rubrica in tutta l'app, sei responsabile di garantire che tutti gli utilizzi di tale rubrica vengano inviati a una singola coda per garantire il corretto funzionamento thread-safe.

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

In alternativa, verificare che non si è prematuramente rilasciando l'ABAddressBookRef sei tornato da ABAddressBookCreateWithOptions(). Ricorda che ABAddressBookRequestAccessWithCompletion() è asincrono.

+0

Ho modificato il post, può essere il problema è relativo a if (addressBookRef! = NULL) CFRelease (addressBookRef); –

6

Vedo che il filo si è schiantato è "com.apple.root.default priorità"

ABAddressBook NON è thread-safe, quindi se si chiama da due fili diversi, viene generata un'eccezione e va in crash l'applicazione.

anche se si inviano sempre le chiamate a DISPATCH_QUEUE_PRIORITY_DEFAULT, può essere eseguito su due thread diversi, perché DISPATCH_QUEUE_PRIORITY_DEFAULT non è una coda seriale.

Usare questo per creare la coda di serie che invia a 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)); 

Ricordati di spedire (sincronizzazione o asincrone) tutte le chiamate alla rubrica a questa coda.

EDIT:

Sembra che si sta chiamando dofetchContacts in un blocco gestore completamento passato nella funzione ABAddressBookRequestAccessWithCompletion. Assicurati di inviare questa chiamata sul thread principale!

La documentazione dice:

Il gestore di completamento viene chiamato su una coda arbitraria. Se la tua app utilizza una rubrica in tutta l'app, sei responsabile di assicurandoti che tutto l'utilizzo di tale rubrica venga inviato a una singola coda per garantire il corretto funzionamento thread-safe.

+0

Attualmente "dofetchContacts:" viene eseguito nel thread principale. "Com.apple.root.default-priority" è una nota di CrashLytics –

+1

No, in realtà questo codice non viene eseguito sul thread principale, perché il gestore di completamento viene chiamato da un coda di sfondo – Felix

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