ABRecordCopyValue 和 ABPropertyID 崩溃

发布于 2024-12-09 19:19:33 字数 1079 浏览 3 评论 0原文

我正在尝试从 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 崩溃。

谢谢!

I'm trying to retrieve data from the iPhone address book and I have some problems.

First of all, I have an array of all contacts (self.allContacts):


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

I also have an array of all properties (each property as string) called self.allKeys.

The crash occurs when I try to get the properties using a property from 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);                                   

The problem is that passing currentFieldProperty to ABRecordCopyValue causes a crash.


  • self.allContacts is an array of all contacts
  • self.allKeys is an array of all properties (each property as string)

When trying to retrieve a single property from ABRecordCopyValue it causes an EXC_BAD_ACCESS crash.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

记忆里有你的影子 2024-12-16 19:19:33

设置 NSZombieEnabledMallocStackLogging在调试器中保护 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 参考CFTypeRef 参考

ABRecordCopyValue - 返回记录属性的值。

<前><代码> CFTypeRef ARecordCopyValue (
ABRecordRef 记录,
ABPropertyID 属性
);

参数
记录 - 包含相关属性的记录。
property - 要返回值的记录的属性。

返回值
记录中的属性值。

并且:

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


 - 以及更多故障排除思路 -

如果不是上述情况,那么当您将 CFTypeRef 转换为 NSString * 时可能会导致崩溃 in (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]);
}

编辑(关于注释):

要将属性名称的字符串转换为其 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]];

Set NSZombieEnabled, MallocStackLogging, and guard malloc in the debugger. Then, when your App crashes, type this in the gdb console:

(gdb) info malloc-history 0x543216

Replace 0x543216 with the address of the object that caused the crash, and you will get a much more useful stack trace and it should help you pinpoint the exact line in your code that is causing the problem.


 - More thoughts -

If self.allKeys is indeed

"an array of all properties (each property as string)"

then you should probably get the intValue of the array object (property) since an ABPropertyID is just a typedef int32_t. Something like:

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

But we would need to see the values in self.allKeys or how it is populated to be sure.

From ABRecordRef Reference and CFTypeRef Reference

ABRecordCopyValue - Returns the value of a record property.

    CFTypeRef ABRecordCopyValue (
       ABRecordRef record,
       ABPropertyID property
    );

Parameters
record - The record containing the property in question.
property - The property of record whose value is being returned.

Return Value
The value of property in record.

And:

ABPropertyID - Integer that identifies a record property.
typedef int32_t ABPropertyID;


 - And more troubleshooting ideas -

If the above is not the case, then your crash may be caused when you cast CFTypeRef to NSString * in (NSString*)ABRecordCopyValue(currentRecordRef, currentFieldProperty) so here is a little helper function that might solve that:

- (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;       
}

Then do currentRecord = [self stringValueForCFType:ABRecordCopyValue(currentRecordRef, currentFieldProperty)]; and check to make sure self.allKeys has an object at index j and self.allContacts has an object at index 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]);
}

Edit (regarding the comments):

To convert string of property name to its int value, you need to create the following (this probably is not be the correct order that they need to be in, so NSLog them first to see what order they need to be in):

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;
}

Then pass stringToABPropertyID: the value from the array [self.allKeys objectAtIndex:j] and you will be returned an ABPropertyID:

currentFieldProperty = [self stringToABPropertyID:[self.allKeys objectAtIndex:j]];
只有一腔孤勇 2024-12-16 19:19:33

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

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

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

I'm posting my earlier comment as an answer:

I would especially give thought to the value of currentFieldProperty - because it is taken out of a dictionary, it is an object but the function is supposed to receive an enumerated value. Maybe try

currentFieldProperty = (ABPropertyID)[[self.allKeys objectAtIndex:j] intValue];
○闲身 2024-12-16 19:19:33

几个问题:

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

Several problems:

  • ABPropertyID is not an object type. (ABPropertyID)[self.allKeys objectAtIndex:j] is clearly wrong. I'm not sure how it's even possible to be "an array of all properties (each property as string)". What string are you talking about? Where did you get this string from? If you are talking about the string of the name of the property e.g. @"kABPersonEmailProperty" then it would be pretty much impossible to get the value of it from that.
  • ABPropertyID values like kABPersonEmailProperty are not constants. They are variables, and they only seem to be initialized after you initialize an address book for the first time.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文