2009-02-24 8 views
13

Chcę wykonać tę samą akcję dla kilku obiektów przechowywanych w NSSet.Kakao NSArray/NSSet: -makeObjectsPerformSelector: kontra szybkie wyliczenie

Moja pierwsza próba przy użyciu szybki liczby:

for (id item in mySetOfObjects) 
    [item action]; 

który działa całkiem dobrze. Potem pomyślałem:

[mySetOfObjects makeObjectsPerformSelector:@selector(action)]; 

A teraz nie wiem, jaki jest najlepszy wybór. O ile rozumiem, oba rozwiązania są równoważne. Ale czy istnieją argumenty przemawiające za preferowaniem jednego rozwiązania nad drugim?

Odpowiedz

21

Chciałbym argumentować za użyciem makeObjectsPerformSelector, ponieważ pozwala obiektowi NSSet dbać o własne indeksowanie, zapętlanie i wysyłanie wiadomości. Ludzie, którzy napisali kod NSSet, najprawdopodobniej znają najlepszy sposób na zaimplementowanie tej konkretnej pętli.

W najgorszym przypadku po prostu zaimplementują dokładnie tę samą pętlę, a wszystko, co zyskasz, będzie nieco czystsze (bez potrzeby stosowania pętli zamykającej). W najlepszym przypadku dokonali wewnętrznych optymalizacji, a kod będzie działał szybciej.

Temat jest krótko wspomniany w dokumencie Apple Code Speed Performance, w sekcji zatytułowanej "Rozwijanie pętli".

Jeśli obawiasz się o wydajność, najlepiej jest skonfigurować szybki program, który wykonuje selektor obiektów w zestawie Czy to uruchomić kilka milionów razy, a czas różnica między dwoma różnymi przypadkami.

+0

Dziękuję za link, nie znałem tego dokumentu! Jak mówisz, sekcja "Rozwijanie pętli" wyraźnie stwierdza, że ​​twórcy kakao dokonali wewnętrznych optymalizacji za pomocą -makeObjectsPerformSelector: – mouviciel

+0

Moja przyjemność. Jest tam trochę ciekawych rzeczy. –

2

makeObjectsPerformSelector: może być nieco szybszy, ale wątpię, aby istniała jakakolwiek praktyczna różnica w 99% przypadków. Jest nieco bardziej zwięzły i czytelny, ale użyłbym go z tego powodu.

4

Nie użyłbym makeObjectsPerformSelector z tego prostego powodu, że jest to rodzaj połączenia, którego nie widzisz zbyt często. Oto dlaczego na przykład - muszę dodać kod debugowania, ponieważ tablica jest wyliczana, a naprawdę nie można tego zrobić z makeObjectsPerformSelector, chyba że zmienisz sposób działania kodu w trybie Release, który jest prawdziwy, nie, nie.

for (id item in mySetOfObjects) 
{ 
    #if MY_DEBUG_BUILD 
    if ([item isAllMessedUp]) 
     NSLog(@"we found that wily bug that has been haunting us"); 
    #endif 

    [item action]; 
} 

--Tom

7

ja też został przedstawiony z tym pytaniem. I znaleźć w docs Apple „Kolekcje Programowanie tematy” pod „Sets: Unordered Collections of Objects” dodaje się:

NSSet metoda objectEnumerator pozwala przemierzacie elementy zestawu jednej o jeden. I themakeObjectsPerformSelector: i makeObjectsPerformSelector: withObject: metody zapewniają wysyłanie wiadomości do pojedynczych obiektów w zestawie. W większości przypadków, szybkie wyliczanie powinno być , ponieważ jest szybsze i bardziej elastyczne niż przy użyciu narzędzia NSEnumerator lub metody makeObjectsPerformSelector: . Aby uzyskać więcej informacji na temat wyliczania, zobacz: "Wyliczenie: przechodzenie przez elementy kolekcji."

To prowadzi mnie do przekonania, że ​​szybkie wyliczanie jest nadal najbardziej efektywnym sposobem dla tej aplikacji.

1

Jeśli jedyną kwestią jest czysta prędkość (np. Gdy tworzysz silnik renderujący, w którym liczy się każdy mały cykl procesora), najszybszym sposobem na przejrzenie dowolnego z obiektów NSCollection (jak iOS 5.0 ~ 6.0) jest różne metody "enumerateObjectsUsingBlock". Nie mam pojęcia, dlaczego tak jest, ale testowałem to i wydaje się, że tak jest ...

Napisałem mały test, tworząc kolekcje setek tysięcy obiektów, z których każdy ma metodę, która sumuje prostą tablicę ints . Każda z tych kolekcji była zmuszona wykonywać miliony razy różne typy iteracji (dla pętli, szybkiego wyliczania, makeObjectsPerformSelector i enumerateObjectsUsingBlock), aw prawie każdym przypadku metody "enumerateObjectsUsingBlock" wygrywały w miarę możliwości podczas testów.

Jedyny przypadek, kiedy to nie było prawdą, to zapełnienie pamięci (gdy zacząłem ją uruchamiać z milionów obiektów), po czym zaczęło tracić na "makeObjectsPerformSelector".

Przykro mi, że nie zrobiłem migawki kodu, ale jest to bardzo prosty test do uruchomienia, bardzo polecam, aby spróbować i przekonać się sam. :)