NSSetからobjectAtIndex:でオブジェクトを取得できない場合、どのようにしてオブジェクトを取得しますか?
セットにはいくつかのユースケースがあります。 (たとえば、 enumerateObjectsUsingBlock
またはNSFastEnumerationを使用して)列挙し、 containsObject
を呼び出してメンバーシップをテストし、 anyObject
は、メンバーを取得する(ランダムではない)か、 allObjects
を使用して配列に変換します(順不同)。
セットは、重複を避け、順序を気にせず、迅速なメンバーシップテストが必要な場合に適しています。
NSSetにはobjectAtIndexメソッドがありません:
すべてのオブジェクトのNSArrayを返すallObjectsを呼び出してみてください。
必要なオブジェクトを選択する一意の識別子がある場合は、filteredSetUsingPredicateを使用できます。
最初に述語を作成します(オブジェクト内の一意のIDが「識別子」と呼ばれ、NSStringであると仮定します):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
そして、述語を使用してオブジェクトを選択します。
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
NSArray *myArray = [myNSSet allObjects];
MyObject *object = [myArray objectAtIndex:(NSUInteger *)]
nSUIntegerを目的のオブジェクトのインデックスに置き換えます。
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:を実装します
- (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
}
ほとんどの場合、セットから1つの特定のオブジェクトを取得することを気にしません。セットにオブジェクトが含まれているかどうかを確認するためのテストが必要です。それがセットの利点です。オブジェクトがコレクションに含まれているかどうかを確認する場合は、配列よりもはるかに高速です。
which取得するオブジェクトを気にしない場合は、-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);
}