Szukam standardowego idiomu do iteracji po tablicy NSArray. Mój kod musi być odpowiedni dla systemu OS X 10.4+.
źródło
Szukam standardowego idiomu do iteracji po tablicy NSArray. Mój kod musi być odpowiedni dla systemu OS X 10.4+.
Generalnie preferowany kod dla wersji 10.5 + / iOS.
for (id object in array) {
// do something with object
}
Ta konstrukcja służy do wyliczania obiektów w kolekcji zgodnej z NSFastEnumeration
protokołem. Takie podejście ma przewagę prędkości, ponieważ przechowuje wskaźniki do kilku obiektów (uzyskane za pomocą pojedynczego wywołania metody) w buforze i iteruje je, przechodząc przez bufor za pomocą arytmetyki wskaźnika. Jest to o wiele szybsze niż wywoływanie za -objectAtIndex:
każdym razem za pośrednictwem pętli.
Warto również zauważyć, że chociaż technicznie możesz użyć pętli for-in, aby przejść przez NSEnumerator
, odkryłem, że to niweluje praktycznie całą przewagę szybkości szybkiego liczenia. Powodem jest to, że domyślna NSEnumerator
implementacja -countByEnumeratingWithState:objects:count:
umieszcza tylko jeden obiekt w buforze przy każdym wywołaniu.
Zgłosiłem to w radar://6296108
(Szybkie wyliczanie NSEnumeratorów jest powolne), ale zostało zwrócone jako Nie do naprawienia. Powodem jest to, że szybkie wyliczanie wstępnie pobiera grupę obiektów, a jeśli chcesz wyliczyć tylko do określonego punktu w wyliczaczu (np. Do momentu znalezienia określonego obiektu lub spełnienia warunku) i użyj tego samego wyliczacza po wyłamaniu pętli często zdarza się, że kilka obiektów zostanie pominiętych.
Jeśli kodujesz w systemie OS X 10.6 / iOS 4.0 i nowszym, możesz również użyć interfejsów API opartych na blokach do wyliczenia tablic i innych kolekcji:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
Możesz także użyć -enumerateObjectsWithOptions:usingBlock:
i przekazać NSEnumerationConcurrent
i / lub NSEnumerationReverse
jako argument opcji.
Standardowym idiomem dla wersji wcześniejszych niż 10.5 jest użycie NSEnumerator
pętli a, a więc:
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
Polecam zachować prostotę. Powiązanie się z typem tablicy jest nieelastyczne, a rzekomy wzrost prędkości używania -objectAtIndex:
jest nieznaczny dla poprawy z szybkim wyliczaniem w wersji 10.5+. (Szybkie wyliczanie faktycznie używa arytmetyki wskaźnika na podstawowej strukturze danych i usuwa większość narzutu wywołania metody). Przedwczesna optymalizacja nigdy nie jest dobrym pomysłem - skutkuje to bałaganem w kodzie, który rozwiązuje problem, który nie jest twoim wąskim gardłem.
Podczas używania -objectEnumerator
bardzo łatwo przechodzisz do innej kolekcji zliczalnej (takiej jak NSSet
, klucze w NSDictionary
itd.), A nawet przełączasz się, -reverseObjectEnumerator
aby wyliczyć tablicę wstecz, bez żadnych innych zmian kodu. Jeśli kod iteracji jest w metodzie, możesz nawet podać dowolny, NSEnumerator
a kod nie musi nawet dbać o to , co iteruje. Ponadto NSEnumerator
(przynajmniej te dostarczone przez kod Apple) zachowuje kolekcję, którą wylicza, o ile jest więcej obiektów, więc nie musisz się martwić o to, jak długo będzie istniał automatycznie wydany obiekt.
Być może największą rzeczą, NSEnumerator
przed którą chroni cię (lub szybkie wyliczenie), jest modyfikowanie kolekcji (tablica lub inna) pod tobą bez twojej wiedzy podczas wyliczania. Jeśli uzyskujesz dostęp do obiektów według indeksu, możesz napotkać dziwne wyjątki lub błędy indywidualne (często długo po wystąpieniu problemu), których debugowanie może być przerażające. Wyliczenie za pomocą jednego ze standardowych idiomów ma działanie „szybkie w razie awarii”, więc problem (spowodowany niepoprawnym kodem) ujawni się natychmiast, gdy spróbujesz uzyskać dostęp do następnego obiektu po wystąpieniu mutacji. Ponieważ programy stają się bardziej złożone i wielowątkowe, a nawet zależą od czegoś, co może modyfikować kod innej firmy, kruchy kod wyliczania staje się coraz bardziej problematyczny. Kapsułkowanie i abstrakcja FTW! :-)
for (id object in array)
, czy istnieje sposób na określenie również bieżącego indeksu obiektów w tablicy, czy też należy uwzględnić osobny licznik?for
pętli:for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
W systemie OS X 10.4.xi wcześniejszych:
W systemie OS X 10.5.x (lub iPhone) i nowszych wersjach:
źródło
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
jest prawdopodobnie najbardziej wydajnym i zwięzłym rozwiązaniem dla tego podejścia.Wyniki testu i kodu źródłowego są poniżej (możesz ustawić liczbę iteracji w aplikacji). Czas jest wyrażony w milisekundach, a każdy wpis to średni wynik uruchomienia testu 5–10 razy. Stwierdziłem, że generalnie jest on dokładny do 2-3 cyfr znaczących, a potem zmienia się z każdym biegiem. Daje to margines błędu mniejszy niż 1%. Test był przeprowadzany na telefonie iPhone 3G, ponieważ była to platforma docelowa, którą byłem zainteresowany.
Klasy dostarczone przez Cocoa do obsługi zestawów danych (NSDictionary, NSArray, NSSet itp.) Zapewniają bardzo przyjemny interfejs do zarządzania informacjami, bez konieczności martwienia się o biurokrację w zarządzaniu pamięcią, realokacji itp. Oczywiście to jednak kosztuje . Myślę, że to całkiem oczywiste, że użycie NSArray of NSNumbers będzie wolniejsze niż C Array of float dla prostych iteracji, więc postanowiłem zrobić kilka testów, a wyniki były dość szokujące! Nie spodziewałem się, że będzie tak źle. Uwaga: testy te są przeprowadzane na telefonie iPhone 3G, ponieważ była to platforma docelowa, którą byłem zainteresowany.
W tym teście dokonuję bardzo prostego porównania wydajności losowego dostępu pomiędzy zmiennoprzecinkową C * i NSArray NSNumbers
Tworzę prostą pętlę, aby podsumować zawartość każdej tablicy i zmierzyć czas za pomocą mach_absolute_time (). NSMutableArray zajmuje średnio 400 razy dłużej !! (nie 400 procent, tylko 400 razy dłużej! to 40 000% dłużej!).
Nagłówek:
// Array_Speed_TestViewController.h
// Test prędkości macierzy
// Utworzony przez Mehmet Akten w dniu 05.02.2009.
// Copyright MSA Visuals Ltd. 2009. Wszelkie prawa zastrzeżone.
Realizacja:
// Array_Speed_TestViewController.m
// Test prędkości macierzy
// Utworzony przez Mehmet Akten w dniu 05.02.2009.
// Copyright MSA Visuals Ltd. 2009. Wszelkie prawa zastrzeżone.
Od: memo.tv
////////////////////
Dostępne od wprowadzenia bloków, pozwala iterować tablicę z blokami. Jego składnia nie jest tak ładna jak szybkie wyliczanie, ale jest jedna bardzo interesująca funkcja: równoczesne wyliczanie. Jeśli kolejność wyliczania nie jest ważna, a zadania można wykonywać równolegle bez blokowania, może to zapewnić znaczne przyspieszenie w systemie wielordzeniowym. Więcej informacji na ten temat w sekcji o równoczesnym wyliczaniu.
/////////// NSFastEnumerator
Ideą szybkiego wyliczania jest użycie szybkiego dostępu do tablicy C w celu zoptymalizowania iteracji. Nie tylko ma być szybszy niż tradycyjny NSEnumerator, ale Objective-C 2.0 zapewnia również bardzo zwięzłą składnię.
/////////////////
NSEnumerator
Jest to forma zewnętrznej iteracji: [myArray objectEnumerator] zwraca obiekt. Ten obiekt ma metodę nextObject, którą możemy wywoływać w pętli, aż zwróci zero
/////////////////
objectAtIndex: wyliczenie
Użycie pętli for, która zwiększa liczbę całkowitą i zapytanie obiektu za pomocą [myArray objectAtIndex: index] jest najbardziej podstawową formą wyliczania.
////////////// Od: darkdust.net
źródło
Trzy sposoby to:
źródło
Dodaj
each
metodę w swoimNSArray category
, będziesz jej bardzo potrzebowaćKod pobrany z ObjectiveSugar
źródło
Oto jak zadeklarować tablicę ciągów i iterować nad nimi:
źródło
Dla Swift
źródło
Zrób to :-
źródło