ABRecordCopyValue和ABPropertyID崩溃
我试图从iPhone通讯录检索数据,我有一些问题。
首先,我有一个所有联系人的数组( self.allContacts
):
ABAddressBookRef abRef = ABAddressBookCreate(); self.allContacts = (NSMutableArray*)ABAddressBookCopyArrayOfAllPeople(abRef);
我也有一个名为self.allKeys
的所有属性(每个属性作为string)的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
是所有属性的数组(每个属性都是string)
当试图从ABRecordCopyValue
检索单个属性时,会导致EXC_BAD_ACCESS
崩溃。
谢谢!
在debugging器中设置NSZombieEnabled , MallocStackLogging和guard malloc 。 然后,当你的应用程序崩溃时,在gdb控制台中input:
(gdb) info malloc-history 0x543216
用导致崩溃的对象的地址replace0x543216,您将得到一个更有用的堆栈跟踪,它应该可以帮助您find导致问题的代码中的确切行。
– 更多的想法 –
如果self.allKeys
确实如此
“所有属性的数组(每个属性都是string)”
那么你应该可能得到数组对象(属性)的intValue
,因为ABPropertyID
只是一个typedef int32_t
。 就像是:
currentFieldProperty = (ABPropertyID)[[self.allKeys objectAtIndex:j] intValue]; ABRecordCopyValue(currentRecordRef, currentFieldProperty)
但是,我们需要在self.allKeys
查看值,或者如何填充值。
从ABRecordRef参考和CFTypeRef参考
ABRecordCopyValue
– 返回logging属性的值。CFTypeRef ABRecordCopyValue ( ABRecordRef record, ABPropertyID property );
参数
record
– 包含有问题的财产的logging。
property
– 正在退还价值的logging的财产。返回值
logging中的财产的价值。
和:
ABPropertyID
– 标识logging属性的整数。
typedef int32_t ABPropertyID;
– 更多的故障排除的想法 –
如果上述情况不是这样,那么当你将CFTypeRef
为(NSString*)ABRecordCopyValue(currentRecordRef, currentFieldProperty)
NSString *
时,可能会导致崩溃(NSString*)ABRecordCopyValue(currentRecordRef, currentFieldProperty)
所以这里有一个辅助函数可以解决这个问题:
- (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]); }
编辑(关于评论):
要将string的属性名称转换为其int值,需要创build以下内容(这可能不是他们需要的正确顺序,所以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]];
我发布我早先的评论作为答案:
我会特别考虑currentFieldProperty的值 – 因为它是从一个字典中取出的,它是一个对象,但是该函数应该接收一个枚举值。 也许试试
currentFieldProperty = (ABPropertyID)[[self.allKeys objectAtIndex:j] intValue];
几个问题:
- ABPropertyID不是一个对象types。
(ABPropertyID)[self.allKeys objectAtIndex:j]
显然是错误的。 我不知道如何甚至可能是“所有属性的数组(每个属性作为string)”。 你在说什么string? 你从哪里得到这个string? 如果你正在谈论属性名称的string,例如@"kABPersonEmailProperty"
那么从它那里得到它的价值几乎是不可能的。 - 诸如
kABPersonEmailProperty
ABPropertyID值不是常量。 它们是variables,而且它们只是在您第一次初始化通讯簿后才初始化。