在OS X(Mac 10.8.2)中,我已将类别添加到ABPerson
,以将电话号码作为Phone
个对象的数组返回。 Phone
对象有两个属性label
和value
。我想获取所有电话号码并过滤它们以仅包含label
匹配输入的那些电话号码。
如果我对整个valueForKey:
数组或使用密钥ABPerson
和@"phones"
的个人使用嵌套@"label"
调用,那么我会得到所需的结果。但是,如果我将valueForKey:
连接到单个valueForKeyPath:
,那么在搜索整个数组时仍然会得到正确的结果,但在评估单个人对象时:
#import <Cocoa/Cocoa.h>
#import <AddressBook/AddressBook.h>
@interface Phone : NSObject
@property (retain) NSString *label;
@property (retain) NSString *value;
@end
@implementation Phone
- (void)dealloc {
self.label = nil;
self.value = nil;
[super dealloc];
}
@end
@interface ABPerson (phones)
- (NSArray *)phones;
@end
@implementation ABPerson (phones)
- (NSArray *)phones {
NSMutableArray *phones = [NSMutableArray array];
ABMultiValue *values = [self valueForProperty:kABPhoneProperty];
for (NSInteger i = 0; i < [values count]; i++) {
Phone *phone = [[Phone alloc] init];
phone.label = ABLocalizedPropertyOrLabel([values labelAtIndex:i]);
phone.value = [values valueAtIndex:i];
[phones addObject:phone];
[phone release];
}
return [NSArray arrayWithArray:phones];
}
@end
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *people = [[ABAddressBook sharedAddressBook] people];
ABPerson *person = [people objectAtIndex:0];
NSArray *a0 = [[people valueForKey:@"phones"] valueForKey:@"label"];
NSArray *a1 = [people valueForKeyPath:@"phones.label"];
NSLog(@"a0 == a1: %d", [a0 isEqualTo:a1]);
NSArray *a2 = [[person valueForKey:@"phones"] valueForKey:@"label"];
NSArray *a3 = [person valueForKeyPath:@"phones.label"];
NSLog(@"a2 == a3: %d", [a2 isEqualTo:a3]);
NSLog(@"people count : %3ld", [people count]);
NSLog(@"people phones label count (valueForKey.valueForKey): %3ld", [a0 count]);
NSLog(@"people phones label count (valueForKeyPath): %3ld", [a1 count]);
NSLog(@"person phones label count (valueForKey.valueForKey): %3ld", [a2 count]);
NSLog(@"person phones label count (valueForKeyPath): %3ld", [a3 count]);
NSLog(@"----------------------------------------------------------");
NSLog(@"people phones label objectAtIndex:0 (valueForKeyPath): %@", [a1 objectAtIndex:0]);
NSLog(@"person phones label (valueForKey.valueForKey): %@", a2);
NSLog(@"person phones label (valueForKeyPath): %@", a3);
[pool release];
return 0;
}
输出:
2013-01-07 15:03:42.537 test[51919:303] a0 == a1: 1
2013-01-07 15:03:42.540 test[51919:303] a2 == a3: 0
2013-01-07 15:03:42.541 test[51919:303] people count : 200
2013-01-07 15:03:42.543 test[51919:303] people phones label count (valueForKey.valueForKey): 200
2013-01-07 15:03:42.544 test[51919:303] people phones label count (valueForKeyPath): 200
2013-01-07 15:03:42.545 test[51919:303] person phones label count (valueForKey.valueForKey): 2
2013-01-07 15:03:42.546 test[51919:303] person phones label count (valueForKeyPath): 0
2013-01-07 15:03:42.547 test[51919:303] ----------------------------------------------------------
2013-01-07 15:03:42.548 test[51919:303] people phones label objectAtIndex:0 (valueForKeyPath): (
mobile,
home
)
2013-01-07 15:03:42.549 test[51919:303] person phones label (valueForKey.valueForKey): (
mobile,
home
)
2013-01-07 15:03:42.551 test[51919:303] person phones label (valueForKeyPath): (null)
为什么[[person valueForKey:@"phones"] valueForKey:@"label"]
不等于[person valueForKeyPath:@"phones.label"]
?这很重要,因为我想使用完整的@"phone.label"
密钥路径对所有联系人使用谓词过滤器,如下所示:
NSString *value = @"home";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY phones.label == %@", value];
NSArray *a4 = [people filteredArrayUsingPredicate:predicate];
在此示例中,a4
始终为空(使用不带“ANY”标志的谓词仍会导致空的过滤数组)。我相信这是因为filteredArrayUsingPredicate:
主要是评估valueForKeyPath:
的每个对象(人),如上所述,这不适用于个人对象。这是对的吗?
如果某人能够了解valueForKeyPath:
对象上ABPerson
失败的原因,或者提供过滤返回所需结果的人员数组的谓词,我将非常感激。< / p>
答案 0 :(得分:3)
ABRecord
这是一个相当古老的问题。 (请参阅此thread on it from 2007;我相信可能会回到10.2中的原始代码。)它们会覆盖valueForKeyPath:
,并且它不会以默认方式运行。密钥必须列在+properties
中。虽然您可以添加自己的属性,但这并没有多大帮助。它将返回在数据库中找到的结果。它永远不会打电话给你的类别方法。并且添加自己的属性会修改AB数据库架构,因此无论如何它都是一个非常大的锤子。你绝对不应该将电话号码复制到一个单独的财产中。
我的建议是将ABPerson
包装到另一个对象中并对其执行查询。这将使您更好地控制记录。
people
上调用它时它会起作用?&#34;这是因为您正在使用另一个特别编写的valueForKeyPath:
版本,即NSArray
覆盖的版本。它会在每条记录上调用valueForKey:
,ABPerson
不会覆盖valueForKey:
,只会valueForKeyPath:
。很奇怪,是吗?
如果这会给您带来麻烦,您应该打开雷达(bugreport.apple.com)。这就是改变这种情况的唯一方法。
这里的another blog帖子解决了同样的问题。他将ABPerson
子类化,而不是包装它。由于ABPerson
是免费桥接到ABPersonRef
,并且没有明确表示您可以将其子类化,因此我可能会使用包装器。但是博客文章可能会给你一些关于这个问题的更深入的见解,而子类化也许没问题。有关此问题的更多信息,请参阅此问题的this even more ancient thread。