ABRecordCopyValue和ABPropertyID崩溃

时间:2011-10-12 20:24:56

标签: iphone objective-c ios abaddressbook

我正在尝试从iPhone地址簿中检索数据,但我遇到了一些问题。

首先,我有一系列所有联系人(self.allContacts):


ABAddressBookRef abRef = ABAddressBookCreate();     
self.allContacts = (NSMutableArray*)ABAddressBookCopyArrayOfAllPeople(abRef);

我还有一个名为self.allKeys的所有属性的数组(每个属性都是字符串)。

当我尝试使用self.allKeys中的属性获取属性时发生崩溃:


NSString *currentRecord = [[NSString alloc] init];
ABRecordRef currentRecordRef;
ABPropertyID currentFieldProperty;

currentRecordRef =  (ABRecordRef)[self.allContacts objectAtIndex:i];
currentFieldProperty = (ABPropertyID)[self.allKeys objectAtIndex:j];

currentRecord = (NSString*)ABRecordCopyValue(currentRecordRef, currentFieldProperty);                                   

问题是将currentFieldProperty传递给ABRecordCopyValue会导致崩溃。


  • self.allContacts是所有联系人的数组
  • self.allKeys是所有属性的数组(每个属性为字符串)

尝试从ABRecordCopyValue检索单个属性时,会导致EXC_BAD_ACCESS崩溃。

谢谢!

3 个答案:

答案 0 :(得分:4)

在调试器中设置NSZombieEnabledMallocStackLoggingguard malloc。然后,当您的应用程序崩溃时,请在gdb控制台中输入:

(gdb) info malloc-history 0x543216

将0x543216替换为导致崩溃的对象的地址,您将获得更有用的堆栈跟踪,它可以帮助您查明代码中导致问题的确切行。


- 更多想法 -

如果self.allKeys确实是

  

“所有属性的数组(每个属性为字符串)”

那么你应该得到数组对象(属性)的intValue,因为ABPropertyID只是typedef int32_t。类似的东西:

currentFieldProperty = (ABPropertyID)[[self.allKeys objectAtIndex:j] intValue];
ABRecordCopyValue(currentRecordRef, currentFieldProperty)

但我们需要查看self.allKeys中的值或如何填充以确定。

来自ABRecordRef ReferenceCFTypeRef Reference

  

ABRecordCopyValue - 返回记录属性的值。

    CFTypeRef ABRecordCopyValue (
       ABRecordRef record,
       ABPropertyID property
    );
     

<强>参数
  record - 包含相关财产的记录。
  property - 正在返回其值的记录的属性。

     

返回值
  记录中的属性值。

  

ABPropertyID - 标识记录属性的整数。
  typedef int32_t ABPropertyID;


- 更多故障排除提示 -

如果不是上述情况,那么当您在CFTypeRef中将NSString *转换为(NSString*)ABRecordCopyValue(currentRecordRef, currentFieldProperty)时可能会导致崩溃,因此这里有一个小助手函数可以解决这个问题:< / p>

- (NSString*)stringValueForCFType:(CFTypeRef)cfValue {
    NSString *stringValue = nil;
    if (!cfValue) return nil;
    CFTypeID cfType = CFGetTypeID(cfValue);
    if (cfType == CFStringGetTypeID()) {
        stringValue = [[(id)CFMakeCollectable(cfValue) retain] autorelease];
    } else if (cfType == CFURLGetTypeID()) {
        stringValue = [(NSURL*)cfValue absoluteString];
    } else if (cfType == CFNumberGetTypeID()) {
        stringValue = [(NSNumber*)cfValue stringValue];
    } else if (cfType == CFNullGetTypeID()) {
        stringValue = [NSString string];
    } else if (cfType == AXUIElementGetTypeID()) {
        stringValue = [[GTMAXUIElement elementWithElement:cfValue] description];
    } else if (cfType == AXValueGetTypeID()) {
        stringValue = [self stringValueForAXValue:cfValue];
    } else if (cfType == CFArrayGetTypeID()) {
        stringValue = [self stringValueForCFArray:cfValue];
    } else if (cfType == CFBooleanGetTypeID()) {
        stringValue = CFBooleanGetValue(cfValue) ? @"YES" : @"NO";
    } else {
        CFStringRef description = CFCopyDescription(cfValue);
        stringValue = [(id)CFMakeCollectable(description) autorelease];
  }
  return stringValue;       
}

然后执行currentRecord = [self stringValueForCFType:ABRecordCopyValue(currentRecordRef, currentFieldProperty)];并检查以确保self.allKeys在索引j处有一个对象,而self.allContacts在索引i处有一个对象:

NSString *currentRecord = [[NSString alloc] init];
ABRecordRef currentRecordRef;
ABPropertyID currentFieldProperty;

if (self.allContacts.count > i) {
    currentRecordRef = (ABRecordRef)[self.allContacts objectAtIndex:i];    
    if (self.allKeys.count > j) {
        currentFieldProperty = (ABPropertyID)[self.allKeys objectAtIndex:j];
        currentRecord = [self stringValueForCFType:ABRecordCopyValue(currentRecordRef, currentFieldProperty)];
    } else {
        NSLog(@"self.allKeys has no value at index (%d): %@", j, [allKeys description]);
    }
} else {
    NSLog(@"self.allContacts has no value at index (%d): %@", i, [allContacts description]);
}

编辑(关于评论):

要将属性名称的字符串转换为其int值,您需要创建以下内容(这可能不是他们需要的正确顺序,因此NSLog他们首先要查看他们需要的顺序():

NSString * const ABPropertyID_toString[] = {
    @"kABPersonFirstNameProperty",
    @"kABPersonLastNameProperty",
    @"kABPersonMiddleNameProperty",
    @"kABPersonPrefixProperty",
    @"kABPersonSuffixProperty",        
    @"kABPersonNicknameProperty", 
    @"kABPersonFirstNamePhoneticProperty",
    @"kABPersonLastNamePhoneticProperty", 
    @"kABPersonMiddleNamePhoneticProperty", 
    @"kABPersonOrganizationProperty", 
    @"kABPersonJobTitleProperty", 
    @"kABPersonDepartmentProperty", 
    @"kABPersonEmailProperty", 
    @"kABPersonBirthdayProperty", 
    @"kABPersonNoteProperty", 
    @"kABPersonCreationDateProperty", 
    @"kABPersonModificationDateProperty", 
    @"kABPersonAddressProperty", 
    // ... etc
};

- (NSString *)ABPropertyIDToString:(ABPropertyID)propertyVal {
    return ABPropertyID_toString[propertyVal];
}

- (ABPropertyID)stringToABPropertyID:(NSString *)propertyString {
    int retVal;
    for(int i=0; i < sizeof(ABPropertyID_toString) - 1; ++i) {
        if([(NSString *)ABPropertyID_toString[i] isEqual:propertyString]) {
            retVal = i;
            break;
        }
    }
    return retVal;
}

然后传递stringToABPropertyID:数组[self.allKeys objectAtIndex:j]中的值,您将返回ABPropertyID

currentFieldProperty = [self stringToABPropertyID:[self.allKeys objectAtIndex:j]];

答案 1 :(得分:0)

我发布了我之前的评论作为答案:

我特别想到currentFieldProperty的值 - 因为它是从字典中取出的,它是一个对象,但该函数应该接收枚举值。也许试试

currentFieldProperty = (ABPropertyID)[[self.allKeys objectAtIndex:j] intValue];

答案 2 :(得分:0)

几个问题:

  • ABPropertyID不是对象类型。 (ABPropertyID)[self.allKeys objectAtIndex:j]显然是错误的。我不确定它是如何成为“所有属性的数组(每个属性为字符串)”。你在说什么字符串?你从哪里得到这个字符串?如果您正在谈论属性名称的字符串,例如@"kABPersonEmailProperty"那么从中获取它的价值几乎是不可能的。
  • kABPersonEmailProperty这样的ABPropertyID值不是常量。它们是变量,它们似乎只是在您第一次初始化地址簿后初始化。