NSOrderedSet vs NSArray indexOfObjectPassingTest:

时间:2013-10-20 15:22:51

标签: ios objective-c nsarray foundation nsorderedset

NSOrderedSet Class Reference概述说:

  

当元素的顺序很重要时,您可以使用有序集作为数组的替代,并且在测试集合中是否包含对象时的性能是一个考虑因素 - 对数组成员资格的测试比测试成员的成员资格要慢集。

哪种方法被视为“会员资格测试”?只是containsObject:?或者,indexOfObjectPassingTest:也会更快吗?

我问,因为如果我只有对象的ID(例如来自服务器)并且想要检查有序集是否包含具有该ID的对象,我将使用indexOfObjectPassingTest:。但是,该方法,因为它测试集合中的每个对象,似乎它与数组一样慢。另一方面,containsObject:似乎更快,因为它利用了NSObject方法hash& isEqual:。我可以使用我拥有的ID创建一个探测对象,然后使用containsObject:。但是,如果有序集已经包含具有该ID的对象,我将丢弃探测对象并更新已在有序集中的对象的属性。首先必须创建探测对象似乎是额外的工作。在这种情况下,是否值得在数组上使用有序集?

另外,我会按日期排序对象,而不是ID。

我使用NSMutableDictionary将对象ID映射到对象,St3fan suggested,但我也希望在UITableView中显示对象。

2 个答案:

答案 0 :(得分:0)

您可以在班级中覆盖-isEqual:-hash。如果你这样做,它将与NSOrderedSet的快速查找一起使用。它可以很简单:

- (BOOL)isEqual:(id)otherObject
{
    return self.myID == otherObject.myID;
}

- (NSUInteger)hash
{
    return self.myID;
}

以下是一个完整的例子:

#import <XCTest/XCTest.h>

@interface MyClass : NSObject
@property (nonatomic) NSInteger myID;
@property (nonatomic, strong) NSDate *date;
@end

@implementation MyClass

- (BOOL)isEqual:(MyClass*)otherObject
{
    return self.myID == otherObject.myID;
}

- (NSUInteger)hash
{
    return self.myID;
}

@end

@interface MyTests : XCTestCase

@end

@implementation MyTests

- (void)testExample
{
    MyClass *obj1 = [[MyClass alloc] init];
    obj1.myID = 1;
    obj1.date = [NSDate dateWithTimeIntervalSince1970:20000];

    MyClass *obj2 = [[MyClass alloc] init];
    obj2.myID = 2;
    obj2.date = [NSDate dateWithTimeIntervalSince1970:10000];

    MyClass *obj3 = [[MyClass alloc] init];
    obj3.myID = 1;
    obj3.date = [NSDate dateWithTimeIntervalSince1970:30000];

    MyClass *obj4 = [[MyClass alloc] init];
    obj4.myID = 3;
    obj4.date = [NSDate dateWithTimeIntervalSince1970:30000];

    NSOrderedSet *set = [[NSOrderedSet alloc] initWithArray:@[obj1, obj2]];
    XCTAssertEqualObjects(((MyClass *)[set firstObject]).date, obj1.date);
    XCTAssertEqualObjects(((MyClass *)[set lastObject]).date, obj2.date);
    XCTAssertTrue([set containsObject:obj1]);
    XCTAssertTrue([set containsObject:obj3]);
    XCTAssertFalse([set containsObject:obj4]);
}

@end

答案 1 :(得分:0)

测试这个的最好方法是编写一些小基准。我不知道你正在处理多少个对象,但如果它少于几百个,那么你可能不会注意到containsObject:indexOfObjectPassingText:之间的差别,甚至只是手动迭代所有对象

听起来NSMutableDictionary实际上更适合您的用例。为什么不将对象存储在由对象ID索引的字典中?然后你可以通过ID快速找到它们,如果需要你也可以轻松地迭代它们。