Aby wyjaśnić cel tego pytania: Wiem JAK tworzyć skomplikowane widoki zarówno z podwidokami, jak i przy użyciu drawRect. Staram się w pełni zrozumieć, kiedy i dlaczego należy używać jednego nad drugim.
Rozumiem też, że nie ma sensu optymalizować tak dużo wcześniej i robić coś trudniejszego przed wykonaniem jakiegokolwiek profilowania. Pomyśl, że czuję się komfortowo z obiema metodami i teraz naprawdę chcę głębszego zrozumienia.
Wiele mojego zamieszania wynika z uczenia się, jak sprawić, by przewijanie widoku tabeli było naprawdę płynne i szybkie. Oczywiście oryginalne źródło tej metody pochodzi od autora Twittera na iPhone'a (dawniej tweetie). Zasadniczo mówi się, że aby przewijanie tabeli było płynne, sekret polega na tym, aby NIE używać podglądów podrzędnych, ale zamiast tego robić wszystkie rysunki w jednym niestandardowym widoku. Zasadniczo wydaje się, że użycie wielu podglądów podrzędnych spowalnia renderowanie, ponieważ mają one dużo narzutów i są stale ponownie zestawiane z widokami nadrzędnymi.
Aby być uczciwym, zostało to napisane, gdy 3GS był całkiem nowy, a iDevices stały się znacznie szybsze od tego czasu. Mimo to ta metoda jest regularnie sugerowana w interwebach i innych miejscach w przypadku tabel o wysokiej wydajności. W rzeczywistości jest to sugerowana metoda w kodzie przykładowego kodu tabeli firmy Apple , została zasugerowana w kilku filmach WWDC ( praktyczne rysowanie dla programistów iOS ) i wielu książkach o programowaniu iOS .
Istnieją nawet niesamowicie wyglądające narzędzia do projektowania grafiki i generowania dla nich kodu Core Graphics.
Więc na początku sądzę, że „istnieje powód, dla którego istnieje Core Graphics. Jest SZYBKI!”
Ale gdy tylko myślę, że przychodzi mi do głowy pomysł „Korzystaj z grafiki rdzenia, kiedy to możliwe”, zaczynam dostrzegać, że drawRect jest często odpowiedzialny za słabą responsywność aplikacji, jest niezwykle kosztowny pod względem pamięci i naprawdę obciąża procesor. Zasadniczo powinienem „ unikać zastępowania drawRect ” (WWDC 2012 iOS App Performance: Graphics and Animations )
Więc myślę, że jak wszystko jest skomplikowane. Może pomożesz sobie i innym zrozumieć, kiedy i dlaczego warto używać drawRect?
Widzę kilka oczywistych sytuacji podczas korzystania z Core Graphics:
- Masz dane dynamiczne (przykład wykresu giełdowego Apple)
- Masz elastyczny element interfejsu użytkownika, którego nie można wykonać za pomocą prostego obrazu o zmiennym rozmiarze
- Tworzysz dynamiczną grafikę, która po wyrenderowaniu jest używana w wielu miejscach
Widzę sytuacje, w których należy unikać Core Graphics:
- Właściwości widoku muszą być animowane osobno
- Masz stosunkowo małą hierarchię widoków, więc każdy dostrzegalny dodatkowy wysiłek przy użyciu CG nie jest wart korzyści
- Chcesz zaktualizować fragmenty widoku bez przerysowywania całości
- Układ widoków podrzędnych należy aktualizować, gdy zmienia się rozmiar widoku nadrzędnego
Więc obdarz swoją wiedzą. W jakich sytuacjach sięgasz po drawRect / Core Graphics (można to również osiągnąć za pomocą podglądów podrzędnych)? Jakie czynniki doprowadziły Cię do takiej decyzji? Jak / dlaczego rysowanie w jednym niestandardowym widoku jest zalecane do płynnego przewijania komórek tabeli, ale Apple odradza drawRect ogólnie ze względu na wydajność? A co z prostymi obrazami tła (kiedy tworzysz je za pomocą grafiki komputerowej, a nie obrazu png o zmiennym rozmiarze)?
Dogłębne zrozumienie tego tematu może nie być potrzebne do tworzenia wartościowych aplikacji, ale nie lubię wybierać między technikami bez możliwości wyjaśnienia dlaczego. Mój mózg się na mnie wścieka.
Aktualizacja pytania
Dziękuję wszystkim za informację. Kilka pytań wyjaśniających:
- Jeśli rysujesz coś z podstawową grafiką, ale możesz osiągnąć to samo dzięki UIImageViews i wstępnie renderowanemu png, czy zawsze powinieneś iść tą drogą?
- Podobne pytanie: Zwłaszcza w przypadku narzędzi takich jak ten , kiedy należy rozważyć rysowanie elementów interfejsu w podstawowej grafice? (Prawdopodobnie gdy wyświetlanie twojego elementu jest zmienne. Np. Przycisk z 20 różnymi wariantami kolorystycznymi. Czy są jakieś inne przypadki?)
- Biorąc pod uwagę moje rozumienie w mojej odpowiedzi poniżej, czy ten sam wzrost wydajności dla komórki tabeli można uzyskać, efektywnie przechwytując bitmapę obrazu komórki po samym renderowaniu złożonego UIView i wyświetlając ją podczas przewijania i ukrywania złożonego widoku? Oczywiście niektóre elementy należałoby opracować. Miałem tylko interesującą myśl.
źródło
Zamierzam zachować podsumowanie tego, co ekstrapoluję na podstawie odpowiedzi innych osób, i zadać wyjaśniające pytania w aktualizacji pierwotnego pytania. Ale zachęcam innych do ciągłego przekazywania odpowiedzi i głosowania na tych, którzy dostarczyli dobrych informacji.
Ogólne podejście
Jest całkiem jasne, że ogólne podejście, jak wspomniał Ben Sandofsky w swojej odpowiedzi , powinno brzmieć: „Kiedy tylko możesz, używaj UIKit. Wykonaj najprostszą implementację, która działa. Profil. Kiedy pojawi się zachęta, zoptymalizuj”.
Dlaczego
Rysowanie zawartości komórek w jednym płaskim UIView może znacznie poprawić FPS na przewijanych tabelach.
Jak powiedziałem powyżej, CPU i GPU to dwa możliwe wąskie gardła. Ponieważ generalnie zajmują się różnymi rzeczami, musisz zwracać uwagę na to, z którym wąskim gardłem się napotykasz. W przypadku przewijanych tabel nie chodzi o to, że Core Graphics rysuje się szybciej i dlatego może znacznie poprawić FPS.
W rzeczywistości grafika podstawowa może być wolniejsza niż zagnieżdżona hierarchia UIView dla początkowego renderowania. Wydaje się jednak, że typowym powodem przerywanego przewijania jest to, że blokujesz GPU, więc musisz się tym zająć.
Dlaczego zastąpienie drawRect (przy użyciu podstawowej grafiki) może pomóc w przewijaniu tabeli:
Z tego, co rozumiem, procesor graficzny nie jest odpowiedzialny za początkowe renderowanie widoków, ale zamiast tego przekazuje tekstury lub mapy bitowe, czasami z pewnymi właściwościami warstw, po ich wyrenderowaniu. Następnie jest odpowiedzialny za kompozycję bitmap, renderowanie wszystkich tych warstw i większości animacji (Core Animation).
W przypadku komórek widoku tabeli GPU może mieć wąskie gardło ze względu na złożone hierarchie widoków, ponieważ zamiast animować jedną bitmapę, animuje widok nadrzędny i wykonuje obliczenia układu widoku podrzędnego, renderuje efekty warstw i komponuje wszystkie podwidoki. Więc zamiast animować jedną bitmapę, jest odpowiedzialny za związek kilku bitmap i ich interakcję dla tego samego obszaru pikseli.
Podsumowując, powodem, dla którego rysowanie komórki w jednym widoku z podstawową grafiką może przyspieszyć przewijanie tabeli, NIE jest to, że rysuje ona szybciej, ale dlatego, że zmniejsza obciążenie GPU, które jest wąskim gardłem powodującym problemy w tym konkretnym scenariuszu .
źródło
Jestem twórcą gier i zadawałem te same pytania, gdy mój przyjaciel powiedział mi, że moja hierarchia widoków oparta na UIImageView spowolni moją grę i sprawi, że będzie straszna. Następnie zacząłem badać wszystko, co mogłem znaleźć, o tym, czy używać UIViews, CoreGraphics, OpenGL lub czegoś innego, jak Cocos2D. Konsekwentna odpowiedź, jaką otrzymałem od przyjaciół, nauczycieli i inżynierów Apple w WWDC, brzmiała, że ostatecznie nie będzie dużej różnicy, ponieważ na pewnym poziomie wszyscy robią to samo . Opcje wyższego poziomu, takie jak UIViews, opierają się na opcjach niższego poziomu, takich jak CoreGraphics i OpenGL, po prostu są opakowane w kod, aby ułatwić korzystanie z nich.
Nie używaj CoreGraphics, jeśli zamierzasz tylko ponownie napisać UIView. Możesz jednak przyspieszyć korzystanie z CoreGraphics, o ile wykonujesz wszystkie rysunki w jednym widoku, ale czy naprawdę warto ? Odpowiedź, którą znalazłem, zwykle brzmi: nie. Kiedy zaczynałem grę, pracowałem z iPhonem 3G. Gdy moja gra stawała się coraz bardziej złożona, zacząłem dostrzegać pewne opóźnienia, ale na nowszych urządzeniach było to całkowicie niezauważalne. Teraz dzieje się dużo akcji, a jedynym opóźnieniem wydaje się być spadek o 1-3 fps podczas grania na najbardziej złożonym poziomie na iPhonie 4.
Mimo to zdecydowałem się użyć Instruments, aby znaleźć funkcje, które zajmowały najwięcej czasu. Okazało się, że problemy nie były związane z korzystaniem z UIViews . Zamiast tego wielokrotnie wywoływał CGRectMake w celu wykonania pewnych obliczeń wykrywania kolizji i ładowania plików obrazu i dźwięku oddzielnie dla niektórych klas, które używają tych samych obrazów, zamiast pobierać je z jednej centralnej klasy pamięci.
Więc ostatecznie możesz być w stanie osiągnąć niewielki zysk z używania CoreGraphics, ale zwykle nie będzie to tego warte lub może nie mieć żadnego efektu. Jedyny raz, kiedy używam CoreGraphics, to rysowanie kształtów geometrycznych, a nie tekstu i obrazów.
źródło