我正在将我一年前为 iOS 6 编写的应用程序升级到 iOS 7/8,我收到了这个 EXC_BAD_ACCESS 错误,这在我的旧版本中从未发生过。
在我的应用程序中,我试图获取某些联系信息,例如名字、姓氏、电话号码、照片。申请流程如下:
1) 点击一个按钮,出现地址簿。
2) 选择任何联系人。
3.1) 如果联系人只有一个电话号码,更新标签。
3.2) 如果联系人有多个电话号码,请在操作表中表示它们,无论用户选择什么号码,都会将该号码更新到 UILabel。
现在,如果一个联系人只有一个电话号码,应用程序可以正常工作而不会崩溃。即 1-->2-->3.1 路径。但是,如果一个联系人有多个电话,并且一旦从操作表中选择了一个联系人号码,它就会在此行崩溃。
CFTypeRef firstNameCF = (__bridge CFTypeRef)(CFBridgingRelease(ABRecordCopyValue(sharedSingleton.personGlobal, kABPersonFirstNameProperty)));
详细代码
1) 选择联系人
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
sharedSingleton.personGlobal = nil;
sharedSingleton.personGlobal=person; // ====> Save a ABRecordRef object globally.
//^^^ Could this be a culprit? I tried to make it private variable also at first.
[self displayAndVerifyPerson]; // No 2 below.
[self dismissViewControllerAnimated:YES completion:^{
}];
return NO;
}
2) 将检查有多少电话号码的人。 0/1/>1.
If 0 show no phone no error.
If 1 phone update label by calling updateLabel.
If >1 represent action sheet for user to select number. And on clickedButtonIndex call updateLabel.
-(void)displayAndVerifyPerson
{
ABMultiValueRef phoneNumbers = ABRecordCopyValue(sharedSingleton.personGlobal,kABPersonPhoneProperty); //ABRecordRef which globally saved.
globalContact=nil; //NSString to store selected number. Works fine.
//self.personGlobal=person;
NSArray *phoneNumberArray = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbers);
CFRelease(phoneNumbers);
if (ABMultiValueGetCount(phoneNumbers) > 0){ //Check if a contact has any number
NSLog(@" Number--> %@",phoneNumberArray); //Prints numbers correct whether no of contacts are 0/1/>1.
if ([phoneNumberArray count]==1){ //If exactly one contact number no problem.
globalContact = [phoneNumberArray objectAtIndex:0];
NSLog(@"--> %@",globalContact);
[self updateLabel]; // No 3 Below.
}
// We have multiple numbers so select any one.
else{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Select Number"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
actionSheet.delegate=self;
actionSheet.tag=0;
for(int i=0;i<[phoneNumberArray count];i++){
[actionSheet addButtonWithTitle:[phoneNumberArray objectAtIndex:i]];
}
[actionSheet addButtonWithTitle:@"Cancel"];
actionSheet.destructiveButtonIndex = actionSheet.numberOfButtons - 1;
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
UIWindow* window = [[[UIApplication sharedApplication] delegate] window];
if ([window.subviews containsObject:self.view])
[actionSheet showInView:self.view];
else
[actionSheet showInView:window];
}
}
else{ //No contact found. Display alert.
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"No contact numebr found."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[av show];
return;
}
}
3) 从 ABRecordRef 对象中获取名字、姓氏和图像。
-(void)updateLabel{
// ----------------- Get First Name From Global ABRecordRef personGlobal---------------------
CFTypeRef firstNameCF = (__bridge CFTypeRef)(CFBridgingRelease(ABRecordCopyValue(sharedSingleton.personGlobal, kABPersonFirstNameProperty)));
^^^^^^^^^^^^^^^^^^^^^^
Crashes only when `updateLabel` called from Actionsheet delegate `clickedButtonAtIndex`
NSString *fName = (NSString *)CFBridgingRelease(firstNameCF);
if ([fName length]==0){
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Contact name not found."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[av show];
return;
}
self.lblFirstName.text = fName; //Set label with first Name.
self.lblHomePhone.text = self.globalContact;//Set number label.
}
4) 操作表委托(delegate)
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *buttonTitle=[actionSheet buttonTitleAtIndex:buttonIndex];
if(actionSheet.tag==0){
//Printing multiple phone numbers which works and prints perfect.
NSLog(@"Lets see what you got: ===> %@",buttonTitle);
if([buttonTitle isEqualToString:@"Cancel"])
return;
globalContact=buttonTitle; // Save contact to NSString for later use.
[self updateLabel]; // No. 3.
}
}
额外说明:
1) 我寻找解决方案的问题(只有 3 个)。
我)ABRecordCopyValue() EXC_BAD_ACCESS Error
ii) EXC_BAD_ACCESS when adding contacts from Addressbook?
iii) kABPersonFirstNameProperty… trowing EXC_BAD_ACCESS
2) Sample project on dropbox if someone is generous/curious enough and wants to run and check.
3)我对这个错误的怀疑:
相同的代码适用于 App Store 上的当前应用程序(为 iOS 6 编写),但在 iOS 7 上崩溃。
可能是由于 Core Foundation 的内存管理。我试图在我使用的任何地方释放 Core Foundation 对象,因为 ARC 不会处理它们。但如果是这种情况,那么当联系人只有一个电话号码时它也应该崩溃。
线程问题?由于应用程序只崩溃了 shen 联系人有多个电话号码,我相信操作表委托(delegate)方法
clickedButtonAtIndex
在后台线程上运行并且出现问题? (只是随机猜测!)我已尽力使我的问题简单易懂且内容丰富。任何建议、评论或解决方案都将不胜感激,因为过去 3 天我一直在努力解决这个问题。谢谢!
最佳答案
你处理 CoreFoundation:
sharedSingleton.personGlobal=person;
=>
因为它不是弧形对象,所以你必须保留它
CFRetain(person);
sharedSingleton.personGlobal=person;
完成后释放
- dealloc {
CFRelease(sharedSingleton.personGlobal);
}
关于ios - ABRecordCopyValue() EXC_BAD_ACCESS Error while getting kABPersonFirstNameProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24320386/