ABRecordCopyValue()EXC_BAD_ACCESS获取kABPersonFirstNameProperty时出错

时间:2014-06-20 05:15:37

标签: ios iphone objective-c ios7 abaddressbook

我正在升级我的应用程序一年前写的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天内摆脱这个问题。谢谢!

2 个答案:

答案 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

的参考