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在索引jself.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,而且它们只是在您第一次初始化通讯簿后才初始化。