我创建了简单的XCTest来测试distinctUnionOfObjects。除isKindOfClass(最后一个XCTAssertTrue)之一外,所有测试用例都通过了。知道为什么在执行distinctUnionOfObjects时会更改类。
- (void)testUsersPredicate
{
NSArray *usersBeforePredicate = [[self userData] users];
XCTAssertEqual([usersBeforePredicate count] , 34u, @"We need 34");
XCTAssertTrue([[usersBeforePredicate lastObject] isKindOfClass:[ICEUsersModelObject class]], @"Object is not ICEUsersModelObject class");
NSString *distinctUsersKeyPath = [NSString stringWithFormat:@"@distinctUnionOfObjects.%@", @"userName"];
NSArray* usersAfterPredicate = [usersBeforePredicate valueForKeyPath:distinctUsersKeyPath];
XCTAssertEqual([usersAfterPredicate count] , 30u, @"We need 30");
XCTAssertTrue([[usersAfterPredicate lastObject] isKindOfClass:[ICEUsersModelObject class]], @"Object is not ICEUsersModelObject class");
}
最佳答案
由于distinctUnionOfObjects
上的右键路径是userName
,因此-valueForKeyPath
:调用将返回不同用户名(不是用户对象)的NSArray
。
从苹果的KVC Programming Guide:
@distinctUnionOfObjects运算符返回一个数组,该数组包含由运算符右侧的键路径指定的属性中的不同对象。
更改最后一个测试用例以检查[NSString class]
,它应该通过。
备择方案
使用相等:
如果应该将userName
属性用作唯一标识符,则可以通过在用户对象上覆盖-isEqual:
和-hash
来体现这一点,从而强制执行该操作:
- (BOOL)isEqual:(id)object {
return ([object isKindOfClass:self.class] && [object.userName isEqual:self.userName]);
}
- (NSUInteger)hash {
return self.userName.hash;
}
这可以使您的整体模型设计受益,并且可以打开许多其他选项,例如这样的选项,它可以收集不同的用户注册表。一行中的userName-
NSSet
用于此时非常快:NSArray *uniqueUsers = [[NSSet setWithArray:users] allObjects];
注意:我将
NSString
的哈希函数重新用于用户哈希,这有一个细微的陷阱。 -[NSString hash]
仅保证最多96个字符的字符串的唯一性!这不在文档中,我花了几乎一天的时间来跟踪生产代码。 (请参阅Apple对CFString.c的实现-搜索__CFStrHashCharacters
)使用NSPredicate:
假设这是一个使用谓词的“创意”解决方案。但是,需要某种迭代,因为否则谓词条件必须是其自身结果的函数:
NSMutableArray *__uniqueUsers = [NSMutableArray array];
[[users valueForKeyPath:@"@distinctUnionOfObjects.userName"] enumerateObjectsUsingBlock:^(id name, NSUInteger idx, BOOL *stop) {
NSArray *uniqueUser = [users filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id user, NSDictionary *bindings) {
return [user.userName isEqual:name];
}]];
if (uniqueUser.count > 0)
[__uniqueUsers addObject:uniqueUser.lastObject];
}];
NSArray *uniqueUsers = [NSArray arrayWithArray:__uniqueUsers];
它获取唯一的用户名集合,对其进行迭代,为每个名称选择一个用户,然后将其添加到输出数组。
关于ios - uniqueUnionOfObjects无法正常工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24397062/