ABRecordCopyValue()EXC_BAD_ACCESS错误

时间:2012-06-24 04:08:56

标签: objective-c ios contacts abaddressbook

在我的应用中,我必须检索用户联系人的某些属性。例如,我需要检索联系人的名字,姓氏,中间名,昵称,组织,职称,部门,生日,电子邮件等。我有一些方法来检索这些属性,只有几个工作,即使他们都非常相似。这是我的一个方法的代码(名字)和一个不是(职称):

+(NSString *)fetchFirstnameForPersonID: (NSUInteger)identifier{

    NSString *firstName;
    ABRecordRef currentPerson = (__bridge ABRecordRef)[[PSAddressBook arrayOfContacts] objectAtIndex:identifier];

    //If the first name property exists
    if ((__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonFirstNameProperty) != NULL){

        firstName = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonFirstNameProperty);        
    }    
    //If the first name property does not exist
    else{
        firstName = @"NULL";
    }
    return firstName;    
}

+(NSString *)fetchJobTitleForPersonID: (NSUInteger)identifier{

    NSString *jobTitle;
    ABRecordRef currentPerson = (__bridge ABRecordRef)[[PSAddressBook arrayOfContacts] objectAtIndex:identifier];

    if ((__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty) != NULL){

        jobTitle = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty);        
    }    
    else{

        jobTitle = @"NULL";
    }
    return jobTitle;    
}

arrayOfContacts是一个定义如下的类方法:

+(NSArray *)arrayOfContacts{

    //Creates an ABAddressBookRef instance containing the data from the address book database
    ABAddressBookRef addressBook = ABAddressBookCreate();

    //Creates an NSArray from the CFArrayRef using toll-free bridging
    NSArray *arrayOfPeople = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);

    CFRelease(addressBook);

    return arrayOfPeople;
}

这些方法在名为“PSPropertyFetcher”的模型类中定义。在我的根视图控制器中,我在viewDidLoad中放置了一些NSLog语句,以查看属性提取器方法是否正常工作。这是我的测试代码:

NSLog(@"Property Fetchers Test\n");

for(NSUInteger i = 0; i <= ([PSAddressBook contactsCount]-1); i++){

    NSLog(@"First Name: %@", [PSPropertyFetcher fetchFirstnameForPersonID:i]);
    NSLog(@"Middle Name: %@", [PSPropertyFetcher fetchMiddlenameForPersonID:i]);
    NSLog(@"Last Name: %@", [PSPropertyFetcher fetchLastnameForPersonID:i]);
    NSLog(@"Organization: %@", [PSPropertyFetcher fetchOrganizationForPersonID:i]);
    NSLog(@"Department: %@", [PSPropertyFetcher fetchDepartmentForPersonID:i]);        
    NSLog(@"Job Title: %@\n\n", [PSPropertyFetcher fetchJobTitleForPersonID:i]);        
}

这只能部分起作用;这是输出:

  

2012-06-27 10:37:30.094猜猜谁![80103:f803]物业骗子测试

     

2012-06-27 10:37:30.108猜猜谁![80103:f803]名字:Jod

     

2012-06-27 10:37:30.114猜猜是谁[80103:f803]中间名:鲍勃

     

2012-06-27 10:37:30.118猜猜谁![80103:f803]姓:Satson

     

2012-06-27 10:37:30.122猜猜谁![80103:f803]组织:强生和约翰逊

     

2012-06-27 10:37:30.125猜猜谁![80103:f803]系:NULL

     

2012-06-27 10:37:30.128猜猜谁![80103:f803]职位名称:NULL


  

2012-06-27 10:37:30.136猜猜谁![80103:f803]名字:Shemairan

     

2012-06-27 10:37:30.166猜猜谁![80103:f803]中间名:戴特兰

     

2012-06-27 10:37:30.179猜猜谁![80103:f803]姓:Catairan

     

2012-06-27 10:37:30.184猜猜谁![80103:f803]组织:Shmairo and Co.

     

2012-06-27 10:37:30.188猜猜谁![80103:f803]部门:NULL

     

2012-06-27 10:37:30.193猜猜谁![80103:f803]职位名称:NULL


  

2012-06-27 10:37:30.202猜猜谁![80103:f803]名字:亚历克斯

     

2012-06-27 10:37:30.207猜猜谁![80103:f803]中间名:约翰

     

2012-06-27 10:37:30.213猜猜谁![80103:f803]姓:玉米

     

2012-06-27 10:37:30.219猜猜谁![80103:f803]组织:Apple

     

2012-06-27 10:37:30.225猜猜谁![80103:f803]系:NULL

     

2012-06-27 10:37:30.230猜猜谁![80103:f803]职位名称:NULL

在iOS模拟器联系人应用程序中,我确保为每个联系人填写每个字段,但由于某种原因,“部门”和“职务”字段无法正确打印。

基本上,我想知道我的“职称”和“部门”提取方法有什么问题。

提前致谢!

4 个答案:

答案 0 :(得分:6)

虽然在地址簿的这么小的样本中看起来不太可能,但你确实在这里发生了内存泄漏,这可能会让事情变得更糟。

假设您使用arrayOfContacts来确定[self contactsCount],那么每次通过这些类方法中的每个循环时,您将泄漏2个AddressBook项。

在这个小样本中,当你启动contactsWithJobTitleProperty时,你只会泄露48个AddressBooks。但是如果你从一个更大的例子中提取这个,你会反复尝试在更大的AddressBook上确定这些值,那么你可能会有数百个悬挂的AddressBook对象。

在下面的代码段中添加CFRelease,看看是否有帮助。

+(NSArray *)arrayOfContacts{

    //Creates an ABAddressBookRef instance containing the data from the address book database
    ABAddressBookRef addressBook = ABAddressBookCreate();

    //Creates an NSArray from the CFArrayRef using toll-free bridging
    NSArray *arrayOfPeople = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFRelease(addressBook);

    return arrayOfPeople;
}

(fwiw,一个会使你的程序崩溃的另一件事是你使用NSUInteger作为你的循环计数器类型,但你测试的值可能是-1 ......并且因为0是NSUInteger的底线,如果您的地址簿中没有联系人,这将失败。但这不是发生此次崩溃的原因。)

答案 1 :(得分:2)

在我看来,您可能正在访问NULL值,在尝试进行桥接传输之前,您是否尝试过测试它是否为NULL?

答案 2 :(得分:1)

这可能无法解决您的问题,但如果我是您,我会做一些调整:

+(NSUInteger)contactsWithJobTitleProperty{
    NSUInteger contactNumber = 0;
    // don't call arrayOfContacts in the loop -- 
    // when you do this you are creating a new address book 
    // each time the loop executes
    NSArray *contacts = [self arrayOfContacts];
    for(NSUInteger increment = 0; increment <= (contacts.count-1); increment++){
        ABRecordRef currentPerson = (__bridge ABRecordRef)[contacts objectAtIndex:increment];
        NSString *valueTest = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonJobTitleProperty);

        if(valueTest != NULL) {
            contactNumber++;
        }
    }
    return contactNumber;
}

另外,@ john.k.doe提到,请务必在CFRelease(addressBook);方法中使用arrayOfContacts

答案 3 :(得分:0)

刚遇到同样的问题。见Jokinryou Tsui的answer here

基本上,如果您有不同的联系人来源,并且它们不是全部(默认),您可能最终会得到与您拉动的联系人数量不匹配的情况,并尝试在不存在的索引处访问ABRecordRef。 ABRecordRef将有一个值(因此单独执行NULL检查不会这样做),但该值将是垃圾,并且在尝试复制其任何值时您将获得BAD ACCESS。

希望这有帮助。