Answers:
一组有几个用例。您可以通过枚举(例如,使用enumerateObjectsUsingBlock
或NSFastEnumeration),调用containsObject
以测试成员资格,用于anyObject
获取成员(不是随机的)或使用进行转换为数组(无特定顺序)allObjects
。
当您不希望重复,不关心订单并希望快速进行成员资格测试时,就可以使用一个集合。
member:
消息来按潜在的副本查找已知对象。如果返回nil
,则该集合不包含等于您传递的对象的对象;如果它返回对象指针,则它返回的指针将指向集合中已存在的对象。集合中的对象必须实现hash
并且isEqual:
对此有用。
hash
不需要执行;如果这样做的话,它只会更快。
hash
NSObject协议的文档:“如果两个对象相等(由isEqual:
方法确定),则它们必须具有相同的哈希值。” 当前,NSObject的实现hash
和isEqual:
使用对象的身份(地址)。如果您覆盖isEqual:
,则将设置对象不相同但相等的可能性-如果您也不覆盖hash
,则对象仍具有不同的哈希值。这违反了相等的对象具有相等的哈希值的要求。
member:
,容器只会看在那一个存储桶(这就是为什么在成员资格测试中集合比数组快得多并且字典在键值查找时比并行数组快得多的原因)。如果所寻找的对象具有错误的哈希,则容器将在错误的存储桶中查找,而找不到匹配项。
-[NSObject hash]
为0。这解释了很多。= S
NSSet没有方法objectAtIndex:
尝试调用allObjects,它返回所有对象的NSArray。
如果您具有某种唯一的标识符来选择所需的对象,则可以使用filteredSetUsingPredicate。
首先创建谓词(假设您在对象中的唯一ID被称为“标识符”,并且它是一个NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
然后使用谓词选择对象:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
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的原因之一。
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
大多数时候,您都不关心从集合中获取一个特定对象。您关心测试以查看集合是否包含对象。这就是集合的优点。当您想查看对象是否在集合中时,集合要比数组快得多。
如果您不关心要获得哪个对象,则使用-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);
}
[[nsSetObjects allObjects] objectAtIndex: anyInteger]