iOS地址簿导入崩溃异常类型:EXC_BAD_ACCESS (SIGSEGV)



首先简要介绍一下背景,我雇佣了一名开发人员来构建我的应用程序,但我知道通过分析现有代码可以更好地学习,所以我的目标是通过这种方式学习更多关于iOS编程的知识,而不是付钱给开发人员来修复。

现在,当我从地址簿导入联系人到应用程序时,应用程序会崩溃。我注意到,当我从iOS Facebook联系人导入联系人时,应用程序会崩溃,但不会从其他联系人组导入联系人。是什么原因造成的呢?

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Triggered by Thread:  0
Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:

研究告诉我,应用程序正在尝试调用它无法访问的东西,但不确定从这里去哪里。

下面是我认为导致问题的代码区域。(这个动作)。

-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
}
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
_arrContactsData =[[NSMutableArray alloc] init];
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
                                        initWithObjects:@[@"", @"", @"", @"", @"", @"", @"", @"", @""]
                                        forKeys:@[@"firstName", @"lastName", @"mobileNumber", @"homeNumber", @"homeEmail", @"workEmail", @"address", @"zipCode", @"city"]];
// Use a general Core Foundation object.
CFTypeRef generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
// Get the first name.
if (generalCFObject) {
    [contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:@"firstName"];
    CFRelease(generalCFObject);
}
// Get the last name.
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
    [contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:@"lastName"];
    CFRelease(generalCFObject);
}
// Get the phone numbers as a multi-value property.
ABMultiValueRef phonesRef = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (int i=0; i<ABMultiValueGetCount(phonesRef); i++) {
    CFStringRef currentPhoneLabel = ABMultiValueCopyLabelAtIndex(phonesRef, i);
    CFStringRef currentPhoneValue = ABMultiValueCopyValueAtIndex(phonesRef, i);
    if (CFStringCompare(currentPhoneLabel, kABPersonPhoneMobileLabel, 0) == kCFCompareEqualTo) {
        [contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:@"mobileNumber"];
    }
    if (CFStringCompare(currentPhoneLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
        [contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:@"homeNumber"];
    }
    CFRelease(currentPhoneLabel);
    CFRelease(currentPhoneValue);
}
CFRelease(phonesRef);

// Get the e-mail addresses as a multi-value property.
ABMultiValueRef emailsRef = ABRecordCopyValue(person, kABPersonEmailProperty);
for (int i=0; i<ABMultiValueGetCount(emailsRef); i++) {
    CFStringRef currentEmailLabel = ABMultiValueCopyLabelAtIndex(emailsRef, i);
    CFStringRef currentEmailValue = ABMultiValueCopyValueAtIndex(emailsRef, i);
    if (CFStringCompare(currentEmailLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
        [contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:@"homeEmail"];
    }
    if (CFStringCompare(currentEmailLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
        [contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:@"workEmail"];
    }
    CFRelease(currentEmailLabel);
    CFRelease(currentEmailValue);
}
CFRelease(emailsRef);

// Get the first street address among all addresses of the selected contact.
ABMultiValueRef addressRef = ABRecordCopyValue(person, kABPersonAddressProperty);
if (ABMultiValueGetCount(addressRef) > 0) {
    NSDictionary *addressDict = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(addressRef, 0);
    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressStreetKey] forKey:@"address"];
    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressZIPKey] forKey:@"zipCode"];
    [contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressCityKey] forKey:@"city"];
}
CFRelease(addressRef);

// If the contact has an image then get it too.
if (ABPersonHasImageData(person)) {
    NSData *contactImageData = (__bridge NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
    [contactInfoDict setObject:contactImageData forKey:@"image"];
}
// Initialize the array if it's not yet initialized.
if (_arrContactsData == nil) {
    _arrContactsData = [[NSMutableArray alloc] init];
}
// Add the dictionary to the array.
[_arrContactsData addObject:contactInfoDict];
// Reload the table view data.

// Dismiss the address book view controller.
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
NSDictionary *info = [_arrContactsData objectAtIndex:0];
self.txfFirstName.text = [info objectForKey:@"firstName"];
self.txfLastName.text = [info objectForKey:@"lastName"];
self.txfMobile.text =[info objectForKey:@"mobileNumber"];
self.txfEmail.text =[info objectForKey:@"homeEmail"];
NSLog(@"Info %@",info);
return NO;
}

看起来Facebook在地址簿中标记其电子邮件联系人很奇怪,因此当您查询标签时它返回nil值,这会给您带来不良访问错误和崩溃

我个人在它周围放了一个if语句,只是忽略了所有的nil地址,因为我只想要工作地址,看看下面的例子在你的代码(我没有检查这个,但它应该工作)

在"分析"我以前的答案后,我注意到它实际上报告了内存泄漏,所以我移动了一点,下面的更新代码不见了。

for (int i=0; i<ABMultiValueGetCount(emailsRef); i++) {
    CFStringRef currentEmailLabel = ABMultiValueCopyLabelAtIndex(emailsRef, i);
    CFStringRef currentEmailValue = ABMultiValueCopyValueAtIndex(emailsRef, i);
    if (currentEmailLabel != nil) {
        if (CFStringCompare(currentEmailLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
            [self.contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:@"workEmail"];
        }
        CFRelease(currentEmailLabel);
    }
    CFRelease(currentEmailValue);
}
CFRelease(emailsRef);//END OF IF WRAPPER

如果你想要邮件而不在乎它们是Facebook我想你可以在标签上做一个nil检查然后重新标签或者完全忽略标签比较

最新更新