我正在尝试从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
崩溃。
谢谢!
答案 0 :(得分:4)
在调试器中设置NSZombieEnabled,MallocStackLogging和guard 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 Reference和CFTypeRef 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)[self.allKeys objectAtIndex:j]
显然是错误的。我不确定它是如何成为“所有属性的数组(每个属性为字符串)”。你在说什么字符串?你从哪里得到这个字符串?如果您正在谈论属性名称的字符串,例如@"kABPersonEmailProperty"
那么从中获取它的价值几乎是不可能的。kABPersonEmailProperty
这样的ABPropertyID值不是常量。它们是变量,它们似乎只是在您第一次初始化地址簿后初始化。