distinctUnionOfObjects无效

时间:2014-06-24 22:00:54

标签: ios objective-c nspredicate distinct-values

我创建了简单的XCTest来测试distinctUnionOfObjects。除了isKindOfClass(Last 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");
}

2 个答案:

答案 0 :(得分:3)

由于distinctUnionOfObjects上的正确密钥路径为userName-valueForKeyPath:调用将返回NSArray个不同的用户名(不是用户对象)。

来自Apple的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;
}

这可以使您的整体模型设计受益,并开辟了许多其他选项,例如获取不同用户reg的集合。 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];

它获取一组唯一的userNames,对其进行迭代,为每个名称选择一个用户,并将其添加到输出数组中。

答案 1 :(得分:1)

你的测试毫无意义。您无法以这种方式使用distinct因为@mvanellen告诉您,您应该更改NSString中的课程,因为您正在搜索不同的username

您反而尝试获取考虑不同用户名的对象列表,但这在概念上是错误的。如果需要,您应该尝试获取用户名列表,而不是整个对象的列表。

考虑进入你的阵列:

ITEM 1: aav / otherValue1

ITEM 2: aav / otherValue2

ITEM 3: matteo / otherValue3

肯定该函数会返回ITEM 3,但是distinct查询,ITEM 1ITEM 2是否需要?

想一想;)