Jeśli nie możesz pobrać obiektu z objectAtIndex: z NSSet, to w jaki sposób możesz odzyskać obiekty?
objective-c
cocoa
cocoa-touch
object
nsset
węzeł ninja
źródło
źródło
[[nsSetObjects allObjects] objectAtIndex: anyInteger]
Odpowiedzi:
Zestaw ma kilka przypadków użycia. Możesz wyliczyć przez (np.
enumerateObjectsUsingBlock
With lub NSFastEnumeration), wywołaćcontainsObject
test członkostwa, użyćanyObject
do pobrania elementu członkowskiego (nie losowego) lub przekonwertować go na tablicę (w dowolnej kolejności) zallObjects
.Zestaw jest odpowiedni, gdy nie chcesz duplikatów, nie dbasz o kolejność i chcesz szybkiego testowania członkostwa.
źródło
member:
wiadomość. Jeśli zwrócinil
, zestaw nie zawiera obiektu równego podanemu; jeśli zwraca wskaźnik do obiektu, to wskaźnik, który zwraca, wskazuje obiekt już w zestawie. Obiekty w zestawie muszą implementowaćhash
iisEqual:
aby było to użyteczne.hash
musi być wdrożony; gdybyś to zrobił, poszłoby znacznie szybciej.hash
protokołu NSObject: „Jeśli dwa obiekty są równe (zgodnie zisEqual:
metodą), muszą mieć tę samą wartość skrótu”. Obecnie implementacje NSObjecthash
iisEqual:
wykorzystują tożsamość (adres) obiektu. Jeśli nadpisujeszisEqual:
, ustawiasz możliwość obiektów, które nie są identyczne, ale są równe - które, jeśli nie zastąpisz równieżhash
, będą nadal miały różne skróty. To narusza wymóg, zgodnie z którym równe obiekty mają równe skróty.member:
zasobniku powinien się znajdować ten obiekt. W przypadku wyszukiwań takich jak kontener będzie wyglądał tylko w tym jednym zasobnik (dlatego zestawy są znacznie szybsze niż tablice podczas testowania członkostwa, a słowniki są o wiele szybsze niż tablice równoległe podczas wyszukiwania klucz-wartość). Jeśli poszukiwany obiekt ma nieprawidłowy skrót, kontener będzie szukał niewłaściwego zasobnika i nie znajdzie dopasowania.-[NSObject hash]
to 0. To wiele wyjaśnia. = SNSSet nie ma metody objectAtIndex:
Spróbuj wywołać allObjects, który zwraca NSArray wszystkich obiektów.
źródło
możliwe jest użycie filterSetUsingPredicate, jeśli masz jakiś unikalny identyfikator do wybrania potrzebnego obiektu.
Najpierw utwórz predykat (zakładając, że Twój unikalny identyfikator w obiekcie nazywa się „identifier” i jest to NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
A następnie wybierz obiekt za pomocą predykatu:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
źródło
NSArray *myArray = [myNSSet allObjects];
MyObject *object = [myArray objectAtIndex:(NSUInteger *)]
zamień NSUInteger na indeks żądanego obiektu.
źródło
Dla Swift3 i iOS10:
//your current set let mySet : NSSet //targetted index let index : Int //get object in set at index let object = mySet.allObjects[index]
źródło
NSSet używa metody isEqual: (której obiekty, które wstawiasz do tego zestawu, muszą dodatkowo przesłonić metodę hash), aby określić, czy wewnątrz niego znajduje się obiekt.
Na przykład, jeśli masz model danych, który definiuje swoją wyjątkowość za pomocą wartości id (powiedzmy, że właściwość to:
@property NSUInteger objectID;
wtedy zaimplementowałbyś isEqual: as
- (BOOL)isEqual:(id)object { return (self.objectID == [object objectID]); }
i możesz zaimplementować hash:
- (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 }
Następnie możesz pobrać obiekt z tym identyfikatorem (a także sprawdzić, czy jest w NSSet) za pomocą:
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
Ale tak, jedynym sposobem na wyciągnięcie czegoś z NSSet jest rozważenie tego, co definiuje jego wyjątkowość w pierwszej kolejności.
Nie testowałem tego, co jest szybsze, ale unikam wyliczania, ponieważ może to być liniowe, podczas gdy użycie metody member: byłoby znacznie szybsze. To jeden z powodów, dla których preferujemy używanie NSSet zamiast NSArray.
źródło
for (id currentElement in mySet) { // ** some actions with currentElement }
źródło
W większości przypadków nie zależy Ci na uzyskaniu jednego konkretnego obiektu z zestawu. Zależy Ci na sprawdzeniu, czy zestaw zawiera obiekt. Do tego nadają się zestawy. Jeśli chcesz sprawdzić, czy obiekt znajduje się w kolekcji, zestawy są znacznie szybsze niż tablice.
Jeśli nie zależy ci na tym, który przedmiot otrzymasz, użyj,
-anyObject
który daje ci tylko jeden przedmiot z zestawu, na przykład włożenie dłoni do torby i złapanie czegoś.Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
Jeśli zależy ci na tym, jaki przedmiot otrzymasz, użyj opcji,
-member
która zwraca obiekt lub nil, jeśli nie ma go w zestawie. Musisz mieć obiekt, zanim go wywołasz.Dog *spot = [Dog dogWithName:@"Spot"]; // ... Dog *aDog = [dogs member:spot]; // Returns the same object as above
Oto kod, który możesz uruchomić w Xcode, aby lepiej zrozumieć
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); }
źródło