回答:
セットにはいくつかの使用例があります。を介して列挙(例:enumerateObjectsUsingBlock
またはNSFastEnumeration)、containsObject
メンバーシップのテストを呼び出すanyObject
、メンバーを取得する(ランダムではない)、またはを使用して配列に変換する(順不同)allObjects
。
セットは、重複を避け、順序を気にせず、迅速なメンバーシップテストが必要な場合に適しています。
member:
メッセージを送信して、重複の可能性がある既知のオブジェクトを検索することもできます。が返されたnil
場合、セットには渡したオブジェクトと同じオブジェクトが含まれていません。オブジェクトポインタを返す場合、返されるポインタは既にセットにあるオブジェクトを指します。セット内のオブジェクトは実装する必要がhash
ありisEqual:
、これが役立つために必要です。
hash
する必要はないと思います。あなたがそれをしたなら、それはただずっと速く行くでしょう。
hash
NSObjectプロトコルのドキュメントから:「2つのオブジェクトが(isEqual:
メソッドによって決定されるように)等しい場合、それらは同じハッシュ値を持つ必要があります。」現在、NSObjectの実装はオブジェクトのID(アドレス)hash
をisEqual:
使用しています。をオーバーライドする場合isEqual:
、同一ではないが等しいオブジェクトの可能性を設定しhash
ます。オーバーライドもしない場合でも、ハッシュは異なります。これは、等しいオブジェクトのハッシュが等しいという要件に違反しています。
member:
場合、コンテナはその1つだけを調べますバケット(これは、セットがメンバーシップテストで配列よりもはるかに高速であり、辞書がキー値ルックアップで並列配列よりもはるかに高速である理由です)。探しているオブジェクトのハッシュが間違っていると、コンテナは間違ったバケットを調べ、一致するものを見つけられません。
-[NSObject hash]
が0 であると誤って思いました。= S
NSSetにはメソッドobjectAtIndexがありません:
すべてのオブジェクトのNSArrayを返すallObjectsを呼び出してみてください。
必要なオブジェクトを選択するための何らかの一意の識別子がある場合は、filteredSetUsingPredicateを使用できます。
最初に述語を作成します(オブジェクト内の一意のIDが「識別子」と呼ばれ、それがNSStringであると仮定します):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
次に、述語を使用してオブジェクトを選択します。
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
Swift3およびiOS10の場合:
//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]
NSSetは、メソッドisEqual:を使用して(そのセットに入れたオブジェクトは、さらにハッシュメソッドをオーバーライドする必要があります)、オブジェクトがその中にあるかどうかを判断します。
したがって、たとえば、一意性を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:メソッドを使用すると、はるかに高速になります。これが、NSArrayではなくNSSetを使用する理由の1つです。
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
ほとんどの場合、特定のオブジェクトをセットから取得する必要はありません。セットにオブジェクトが含まれているかどうかを確認するためのテストに関心があります。それがセットが良いことです。オブジェクトがコレクション内にあるかどうかを確認する場合、セットは配列よりもはるかに高速です。
取得するオブジェクトが気にならない場合-anyObject
は、バッグに手を入れて何かをつかむなど、セットから1つのオブジェクトを取得するだけを使用します。
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]