distinctUnionOfObjects

distinctUnionOfObjects

我创建了简单的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/

10-10 06:40