从NSSet获取对象


Answers:


139

一组有几个用例。您可以通过枚举(例如,使用enumerateObjectsUsingBlock或NSFastEnumeration),调用containsObject以测试成员资格,用于anyObject获取成员(不是随机的)或使用进行转换为数组(无特定顺序)allObjects

当您不希望重复,不关心订单并希望快速进行成员资格测试时,就可以使用一个集合。


7
您还可以通过向集合发送member:消息来按潜在的副本查找已知对象。如果返回nil,则该集合不包含等于您传递的对象的对象;如果它返回对象指针,则它返回的指针将指向集合中已存在的对象。集合中的对象必须实现hash并且isEqual:对此有用。
彼得·霍西

@PeterHosey我认为hash 不需要执行;如果这样做的话,它只会更快。
fumoboy007

2
@ fumoboy007:是的,它可以存储在集合中或用作字典中的键。来自hashNSObject协议的文档:“如果两个对象相等(由isEqual:方法确定),则它们必须具有相同的哈希值。” 当前,NSObject的实现hashisEqual:使用对象的身份(地址)。如果您覆盖isEqual:,则将设置对象不相同但相等的可能性-如果您也不覆盖hash,则对象仍具有不同的哈希值。这违反了相等的对象具有相等的哈希值的要求。
彼得·霍西

1
@ fumoboy007:考虑一个哈希表的工作原理:该容器具有一定数量桶的数组,并使用每个传入对象的哈希值,以确定哪些一桶对象应该是在查找如member:,容器只会看在那一个存储桶(这就是为什么在成员资格测试中集合比数组快得多并且字典在键值查找时比并行数组快得多的原因)。如果所寻找的对象具有错误的哈希,则容器将在错误的存储桶中查找,而找不到匹配项。
彼得·霍西

@PeterHosey Oops…我错误地认为的默认实现-[NSObject hash]为0。这解释了很多。= S
fumoboy007

31

NSSet没有方法objectAtIndex:

尝试调用allObjects,它返回所有对象的NSArray。


您是否知道返回的数组是否已订购?换句话说,如果我使用“ setByAddingObject”将对象添加到集合中,而我使用“ allObjects”,是吗?数组中的元素按我添加对象的顺序排序?
iosMentalist 2012年

只需使用NSSortPredicate对结果数组进行排序,就可以了
Jason

如果您只对一个特定对象感兴趣,最好使用filteredSetUsingPredicate方法。
akw

17

如果您具有某种唯一的标识符来选择所需的对象,则可以使用filteredSetUsingPredicate。

首先创建谓词(假设您在对象中的唯一ID被称为“标识符”,并且它是一个NSString):

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];

然后使用谓词选择对象:

NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;

13

NSArray *myArray = [myNSSet allObjects];

MyObject *object = [myArray objectAtIndex:(NSUInteger *)]

将NSUInteger替换为所需对象的索引。


1
应该是:MyObject * object = [myArray objectAtIndex:(NSUInteger *)]
John D.

8

对于Swift3和iOS10:

//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]

6

NSSet使用方法isEqual:(您放入该集中的对象还必须覆盖该对象,此外,还应使用hash方法)来确定对象是否在其中。

因此,例如,如果您有一个通过id值定义其唯一性的数据模型(例如,该属性为:

@property NSUInteger objectID;

那么您将实现isEqual:as

- (BOOL)isEqual:(id)object
{
  return (self.objectID == [object objectID]);
}

您可以实现哈希:

- (NSUInteger)hash
{
 return self.objectID;  // to be honest, I just do what Apple tells me to here
                       // because I've forgotten how Sets are implemented under the hood
}

然后,您可以通过以下方式获取具有该ID的对象(以及检查其是否在NSSet中):

MyObject *testObject = [[MyObject alloc] init];
testObject.objectID = 5; // for example.  

// I presume your object has more properties which you don't need to set here 
// because it's objectID that defines uniqueness (see isEqual: above)

MyObject *existingObject = [mySet member: testObject];

// now you've either got it or existingObject is nil

但是,是的,从NSSet中获取某些东西的唯一方法是首先考虑定义其唯一性的东西。

我没有测试更快的方法,但是我避免使用枚举,因为这可能是线性的,而使用member:方法会更快。这就是更喜欢使用NSSet而不是NSArray的原因之一。



0

大多数时候,您都不关心从集合中获取一个特定对象。您关心测试以查看集合是否包含对象。这就是集合的优点。当您想查看对象是否在集合中时,集合要比数组快得多。

如果您不关心要获得哪个对象,则使用-anyObject哪个对象就可以从集合中获得一个对象,例如将您的手放在包中并抓住东西。

Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects

如果您关心得到的对象,则使用-member它可以将对象退还给您;如果不在集合中,则使用nil。调用对象之前,您需要已经拥有该对象。

Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above

您可以在Xcode中运行以下代码来了解更多信息

NSString *one = @"One";
NSString *two = @"Two";
NSString *three = @"Three";

NSSet *set = [NSSet setWithObjects:one, two, three, nil];

// Can't use Objective-C literals to create a set.
// Incompatible pointer types initializing 'NSSet *' with an expression of type 'NSArray *'
//  NSSet *set = @[one, two, three];

NSLog(@"Set: %@", set);
// Prints looking just like an array but is actually not in any order
//Set: {(
//     One,
//     Two,
//     Three
//     )}

// Get a random object
NSString *random = [set anyObject];
NSLog(@"Random: %@", random); // Random: One

// Iterate through objects. Again, although it prints in order, the order is a lie
for (NSString *aString in set) {
    NSLog(@"A String: %@", aString);
}

// Get an array from the set
NSArray *array = [set allObjects];
NSLog(@"Array: %@", array);

// Check for an object
if ([set containsObject:two]) {
    NSLog(@"Set contains two");
}

// Check whether a set contains an object and return that object if it does (nil if not)
NSString *aTwo = [set member:two];
if (aTwo) {
    NSLog(@"Set contains: %@", aTwo);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.