我正在升级我的应用程序一年前写的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)操作表委派
-(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个)。
i)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上的当前App(针对iOS 6编写),但是针对iOS 7崩溃。
可能是由于Core Foundation的内存管理。我尝试在我使用的任何地方发布Core Foundation对象,因为ARC没有处理它们。但如果是这种情况,那么它也应该崩溃,而联系人只有一个电话号码。
线索问题?由于应用程序仅崩溃了shen联系人有多个电话号码,我相信在后台线程上运行的操作表委托方法clickedButtonAtIndex
出错了? (只是随机猜测!)
我试图让我的问题变得简单而且信息量最大。任何建议,评论或解决方案将不胜感激,因为我一直试图在过去3天内摆脱这个问题。谢谢!
答案 0 :(得分:2)
你处理CoreFoundation:
sharedSingleton.personGlobal=person;
=&GT;
因为它不是弧形对象,所以你必须保留它
CFRetain(person);
sharedSingleton.personGlobal=person;
完成后释放
- dealloc {
CFRelease(sharedSingleton.personGlobal);
}
答案 1 :(得分:1)
忽略了很多代码的奇怪之处,根本问题在于你没有保留你想要使用的值超出它所呈现的范围。具体来说,我指的是person
变量在第1节中,您不保留此变量,因此可以在范围结束后随时释放它(可能会这样做)。因此,一旦你开始调用updateLabel
,它就只是一个悬空指针。要解决此问题,您应该将其设为强变量。
但是等一下......那只是对于Objective-C对象,所以你需要对该属性进行更多的装饰。您可以添加__attribute__((NSObject))
以使此类型的行为与NSObject
一样,并受ARC限制。我找不到关于此的文档了,但这里有an old Apple Mailing List Thread