【问题标题】:ABRecordCopyValue() EXC_BAD_ACCESS ErrorABRecordCopyValue() EXC_BAD_ACCESS 错误
【发布时间】:2012-06-24 04:08:56
【问题描述】:

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

+(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”的模型类中定义。在我的根视图控制器中,我将一些 NSLog 语句放入 viewDidLoad 以查看属性获取器方法是否正常工作。这是我的测试代码:

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] 名字:乔德

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] 名字:Shemailan

2012-06-27 10:37:30.166 猜猜是谁![80103:f803] 中间名:Daitran

2012-06-27 10:37:30.179 猜猜是谁![80103:f803] 姓:卡泰兰

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] 名字:Alex

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 模拟器联系人应用程序中,我确保为每个联系人填写了每个字段,但由于某种原因,“部门”和“职位”字段没有正确打印。

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

提前致谢!

【问题讨论】:

  • 可以看看[self arrayOfContacts]的实现吗?如果它只是一个属性,它在哪里填充?
  • @JakeKing 我更新问题以显示arrayOfContacts

标签: objective-c ios contacts abaddressbook


【解决方案1】:

虽然在如此小的地址簿样本上似乎不太可能,但这里确实存在内存泄漏,可能会导致事情崩溃。

假设您使用arrayOfContacts 来确定@​​987654322@,则每次通过这些类方法中的每个循环都会泄漏2 个地址簿项。

在这个小示例中,当您启动 contactsWithJobTitleProperty 时,您只会泄露 48 个地址簿。但是,如果您从一个更大的示例中提取这一点,在该示例中您反复尝试在更大的 AddressBook 上确定这些值,您可能会有数百个悬空的 AddressBook 对象。

在下面的sn-p中添加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 的下限,如果您的通讯录中没有联系人,这将失败。但这不是发生此崩溃的原因。)

【讨论】:

  • 我会尝试并回复您。
  • 现在它没有崩溃并且组织方法返回正确的值,但是其他属性的一些其他方法没有返回正确的值。
  • 什么“组织”方法? (我想我可以假设您的意思是您有另一个类方法,例如上面的方法,它检索具有属性 kABPersonOrganizationProperty 的联系人数量。)还有哪些其他方法不返回正确的值?当您检索它们时,并非所有类型都返回相同的类型,因此您必须确保您的 __bridge 或 _bridge_transfer 在每种情况下都有意义。
  • 对不起。职位名称方法返回填写职位名称属性的联系人数量。组织方法相同,但检查组织属性。对于这样的每种方法,我都有一个__bridge_transfer(我对每个属性都有一个方法,总共 31 个)。在什么情况下__bridge_transfer 没有意义?
  • 对不起,我不清楚。我的意思是 __bridge 或 __bridge_transfer 中使用的类型。我认为您在每种情况下都正确使用了 __bridge/__bridge_transfer,但是从地址簿返回的类型可能并不总是传输到 NSString 的类型,并且如果您从不是string 到 NSString,我认为你可能会遇到麻烦。
【解决方案2】:

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

【讨论】:

  • 我不测试它是否为 NULL 值(我应该非常感谢),但我确保为模拟器中每个字段的每个联系人添加一个值。
【解决方案3】:

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

+(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 提到,请确保在您的 arrayOfContacts 方法中使用 CFRelease(addressBook);

【讨论】:

  • 谢谢!我更改了我的代码,因此现在我在 for 循环之前创建了一个像 NSArray *contacts = [PSAddressBook arrayOfContacts] 这样的地址簿。我还将CFRelease(addressBook) 行添加到arrayOfContacts
【解决方案4】:

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

基本上,如果您有不同的联系人来源可用,并且它们并非都是本地的(默认设置),那么您最终可能会发现您拉动的联系人数量不匹配,然后尝试在不存在的索引处访问 ABRecordRef。 ABRecordRef 将有一个值(因此单独的 NULL 检查不会执行此操作),但该值将是垃圾,并且在尝试复制其任何值时您将获得 BAD ACCESS。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-26
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多