pentru a drawRect sau nu să drawRect (când ar trebui să o utilizați drawRect/Core Graphics vs subviews/imagini și de ce?)

Pentru a clarifica scopul acestui întrebare: știu CUM de a crea complicat opinii cu atât subviews și folosind drawRect. Am'm încercarea de a înțelege pe deplin atunci când's și de ce's pentru a utiliza unul peste celălalt. De asemenea, am înțeles că nu't face sens pentru a optimiza atât de mult înainte de timp, și de a face ceva mai dificil drum înainte de a face orice profil. Consider ca m-am'm confortabil cu ambele metode, și acum doresc cu adevărat o înțelegere mai profundă. O mulțime de confuzia mea vine de la a învăța cum să facă tabel de parcurgere performanta foarte buna si rapida. Desigur, sursa originală a acestei metode este de autor spatele twitter pentru iPhone (fosta tweetie). Practic, se spune că pentru a face masa de unt defilare netedă, secretul este să NU folosiți subviews, dar în loc să facă tot desenul în unul personalizat uiview. În esență, se pare că, folosind o mulțime de subviews incetineste redare în jos, deoarece acestea au o mulțime de deasupra capului, și sunt în mod constant re-compuse lor de vedere mamă. Pentru a fi corect, acest lucru a fost scris atunci când 3GS a fost destul de brand premieră noul, și iDevices au ajuns mult mai repede de atunci. Încă această metodă periodic a sugerat pe interwebs și în altă parte pentru înaltă performanță mese. În fapt, aceasta's o metodă sugerată în Mar's de Masă Sample Code, a fost sugerat în mai multe videoclipuri WWDC (Practice de Desen pentru Dezvoltatorii iOS), și multe iOS cărți de programare. Există chiar și minunat în căutarea de instrumente]9 pentru design grafic și de a genera Grafică de Bază cod pentru ele. Deci, la început, am'm duce să cred că "nu e un motiv Grafică de Bază există. Este RAPID!" Dar de îndată ce cred că am înțeles ideea "Favoare Grafică de Bază, atunci când este posibil", am început să văd că drawRect este de multe ori responsabil pentru săraci capacitatea de reacție într-o aplicație, este extrem de scump memorie înțelept, și într-adevăr impozite CPU. Practic, asta ar trebui să "a Evita imperative drawRect" (WWDC 2012 iOS App de Performanță: Grafică și Animații) Deci, cred, ca totul, l's-a complicat. Poate te pot ajuta eu și ceilalți să înțeleagă atunci Când's și de Ce's pentru utilizarea drawRect? Văd un cuplu evidente situații de utilizat Grafică de Bază:

  1. Ai dinamice de date (Măr's Stoc Diagramă exemplu)
  2. Ai un UI flexibil element care poate't fi executat cu un simplu redimensionarea imaginii
  3. Creați un grafic dinamic, care odată prestate este utilizat în mai multe locuri Am văzut situații, pentru a evita Grafică de Bază:
  4. Proprietăți de vedere trebuie să fie animat separat
  5. Ai un relativ mici vedere ierarhic, astfel orice perceput un efort suplimentar folosind CG e't merită să câștige
  6. Doriți să actualizați piese de vedere, fără a retrasarea totul
  7. Aspectul de subviews are nevoie pentru a actualiza atunci când părintele vedere modificările de dimensiune Așa da-ți cunoștințele. În ce situații nu vă ajunge pentru drawRect/Grafică de Bază (care ar putea fi, de asemenea, realizat cu subviews)? Ce factori conduce la această decizie? Cum/de Ce este desen într-o vizualizare personalizată recomandat pentru unt buna celulă de tabel defilare, dar Apple sfatuieste drawRect împotriva pentru motive de performanță, în general? Ce zici de imagini de fundal simple (când le creați cu CG vs folosind un redimensionabilă imagine png)? O înțelegere profundă a acestui subiect nu pot fi necesare pentru a face util aplicații, dar eu nu't dragostea alegerea între tehnici, fără a fi în măsură să explice de ce. Creierul meu se supara pe mine.

    Actualizare Întrebare ##

    Multumesc pentru informatii toată lumea. Unele întrebări de clarificare aici:

  8. Dacă sunteți de desen ceva cu grafică de bază, dar se poate realiza acelasi lucru cu UIImageViews și un pre-randat, png, ar trebui să întotdeauna merge pe acest drum?
  9. O întrebare similară: mai Ales cu tare instrumente, cum ar fi acest lucru, când ar trebui să ia în considerare desen elemente de interfață în core graphics? (Probabil că atunci când afișajul de element este variabila. de exemplu, un buton cu 20 de variante de culori diferite. Orice alte cazuri?)
  10. Având în înțelegerea mea în răspunsul meu de mai jos, ar putea la fel de câștiguri de performanță pentru o celulă de tabel, eventual, să fie câștigat de eficient captura o imagine bitmap de celulă după complexă UIView face's în sine, și afișarea în timp ce defilare și să-ți ascunzi complex de vedere? Evident, unele piese ar trebui să fie elaborat. Doar un gând interesant am avut.
Soluția

Stick la UIKit și subviews ori de câte ori puteți. Puteți fi mai productiv, și să profite de toate OO mecanisme care ar trebui să lucrurile mai ușor să se mențină. Utilizare Grafică de Bază, atunci când poate't obține performanță ai nevoie de UIKit, sau încercarea de a hack împreună efecte de desen în UIKit ar fi mai complicat.

Fluxul general de lucru ar trebui să fie pentru a construi tableviews cu subviews. Utilizați Instrumente pentru a măsura rata de cadru la cea mai veche hardware-ului dvs. aplicație va sprijini. Dacă poți't obține 60fps, drop jos pentru a CoreGraphics. Când te'am făcut acest lucru pentru un timp, veți obține un sentiment de când UIKit este, probabil, o pierdere de timp.

Deci, de ce este Core Graphics rapid?

CoreGraphics e't foarte repede. Daca's a fi folosit tot timpul,'re, probabil, de gând lent. L's un desen bogat API, care necesită activitatea sa fi facut pe CPU, spre deosebire de o mulțime de UIKit muncă, care este descărcat la GPU. Dacă ați avut de a anima o minge în mișcare pe ecran, ar fi o idee teribil de apel setNeedsDisplay pe o vizualizare de 60 de ori pe secundă. Deci, dacă aveți sub-componente de punctul dumneavoastră de vedere, care trebuie să fie animat individual, fiecare componentă ar trebui să fie un strat separat.

Cealaltă problemă este că, atunci când don't face desen personalizat cu drawRect, UIKit poate optimiza stoc vedere atât drawRect este un nu-op, sau se poate lua comenzi rapide cu compunere. Când înlocuiți drawRect, UIKit trebuie să ia calea lentă pentru că habar n-are ce're face.

Aceste două probleme pot fi compensate de beneficiile în caz de tabel celule. După drawRect se numește atunci când o vezi prima apare pe ecran, conținutul sunt în cache, și defilare este o simplă traducere efectuată de către GPU. Pentru că tu're de-a face cu un singur punct de vedere, mai degrabă decât o ierarhie complexă, UIKit's drawRect optimizări devin mai puțin importante. Deci strangulare devine cât de mult vă puteți optimiza dvs. de Grafică de Bază de desen.

Ori de câte ori puteți, utilizați UIKit. Face cea mai simplă implementare care lucrează. De profil. Atunci când nu's un stimulent, pentru a optimiza.

Comentarii (0)

Diferența este că UIView și CALayer, în esență, înțelegerea în imagini fixe. Aceste imagini sunt încărcate la placa grafica (daca stii OpenGL, cred că de o imagine ca o textură și o UIView/CALayer ca un poligon arată astfel o textura). Odată ce o imagine este pe GPU, nu pot fi trase foarte repede, și chiar de mai multe ori, și (cu o mica penalizare de performanță), chiar și cu diferite niveluri de transparență alfa pe partea de sus de alte imagini.

CoreGraphics/Cuarț este un API pentru generatoare imagini. Este nevoie de un pixel tampon (din nou, cred că OpenGL textura) și modificări pixelii individuali în interiorul acestuia. Toate astea se întâmplă în RAM și CPU, și doar o singură dată de Cuarț se face, nu imaginea obține "aruncat" înapoi la GPU. Acest round-trip de a obține o imagine de GPU-ului, schimba-l, apoi încărcarea întreaga imagine (sau cel puțin o relativ mare parte din ea) înapoi la GPU-ului este destul de lent. De asemenea, efective de desen pe care Cuarț face, în timp ce foarte repede pentru ceea ce faci, este mult mai lent decât ceea ce GPU are.

Ca's evidentă, având în vedere GPU-ului este în mare parte se deplasează în jurul valorii de pixeli neschimbate în bucăți mari. Cuarț are acces aleatoriu de pixeli și acțiuni CPU cu rețea, audio, etc. De asemenea, dacă aveți mai multe elemente pe care le desena folosind Cuarț, în același timp, trebuie să re-trage toate dintre ele atunci când se schimbă, apoi încărcați întregul bucată, în timp ce dacă modificați o imagine și apoi să UIViews sau CALayers lipiți-l pe alte imagini, puteți obține departe cu încărcarea mult mai mici cantități de date pentru a GPU-ului.

Când don't pună în aplicare -drawRect:, cele mai multe puncte de vedere pot fi optimizate departe. Ei nu't conține nici pixeli, deci poate't desena ceva. Alte puncte de vedere, ca UIImageView, doar trage o UIImage (care, din nou, este, în esență, o trimitere la o textura, care probabil a fost deja încărcată pe GPU). Deci, dacă vă trage la fel UIImage 5 ori folosind un UIImageView, este încărcat doar la GPU-o dată, și apoi trase la ecran, în 5 locații diferite, economisind timp și ne CPU.

Atunci când implementați -drawRect:, acest lucru provoacă o nouă imagine pentru a fi creat. Apoi trage în care pe CPU folosind Cuarț. Dacă ai trage o UIImage în drawRect, probabil popularitate imaginea de pe GPU, copii în imaginea pe care're desen, și odată ce ai're făcut, încărcări acest al doilea exemplar de imaginea înapoi la placa grafica. Deci're folosind de două ori GPU-ului de memorie pe dispozitiv.

Deci, cel mai rapid mod de a desena este, de obicei, pentru a păstra conținutul static separat de schimbare de conținut (în separat UIViews/UIView subclase/CALayers). Încărcare conținut static ca un UIImage și trage-l folosind un UIImageView și a pus conținutul generat dinamic în timpul rulării într-un drawRect. Dacă aveți conținut care se trase în mod repetat, dar de la sine nu't schimba (I. e. 3 icoane, care sunt afișate în același slot pentru a indica un statut) utilizarea UIImageView la fel de bine.

O precizare: nu Există un astfel de lucru ca având prea multe UIViews. Deosebit de zone transparente ia o mai mare taxă pe GPU-ului pentru a trage, pentru că ei au nevoie să fie amestecat cu alte pixeli spatele lor atunci când sunt afișate. Acesta este motivul pentru care puteți marca un UIView ca "opac", pentru a indica pentru a GPU-ului, care poate distruge totul în spatele imaginii.

Dacă aveți conținut care este generat dinamic la runtime, dar rămâne la fel pentru durata de aplicare's viață (de exemplu, o etichetă care conține numele de utilizator) se poate face de fapt sens doar pentru a trage totul o dată cu Cuarț, cu text, butonul de frontieră etc., ca parte din fundal. Dar asta's, de obicei, o optimizare care's nu este necesar doar dacă Instrumentele app vă spune altfel.

Comentarii (6)

Am'm de gând să încercați și să păstreze un rezumat a ceea ce am'm extrapolarea la alte's răspunsuri aici, și de a pune întrebări de clarificare într-o actualizare la întrebarea inițială. Dar am încuraja pe alții să păstreze răspunsurile vin și să voteze pe cei care au oferit informații.

Abordare Generală

L's destul de clar că abordarea generală, ca Ben Sandofsky menționat în răspunsul lui, ar trebui să fie "ori de câte ori puteți, utilizați UIKit. Face cea mai simplă implementare care lucrează. De profil. Atunci când nu's un stimulent, pentru a optimiza."

Ce

  1. Există două principalele blocaje posibile într-un iDevice, CPU și GPU-ului
  2. CPU este responsabil pentru primul desen/prestarea de vedere
  3. GPU-ul este responsabil pentru o majoritate de animație (Core Animation), efecte de strat, compunere, etc.
  4. UIView are o mulțime de optimizări, cache, etc, construit în pentru manipularea complex de vedere ierarhii
  5. Când imperative drawRect pierzi o mulțime de beneficii UIView's furnizeze, și-l's, în general, mai lent decât să UIView se ocupe de redare.

Desen celule conținutul într-un apartament UIView poate îmbunătăți foarte mult FPS-ul pe defilare tabele.

Cum am spus mai sus, CPU și GPU sunt două posibile blocaje. Deoarece în general se ocupe de lucruri diferite, trebuie să acorde o atenție la care strangulare se execută împotriva. În caz de defilare tabele, l's nu Grafică de Bază este de a atrage mai repede, și că's de ce se poate îmbunătăți foarte mult FPS-ul.

În fapt, Grafică de Bază poate fi foarte bine mai lent decât un imbricate UIView ierarhie pentru primele face. Cu toate acestea, se pare că motivul tipic pentru instabil defilare este că sunt deblocărilor GPU-ului, astfel încât aveți nevoie pentru a adresa asta.

De ce imperative drawRect (folosind grafică de bază) poate ajuta la masă derulare:

Din ce am inteles, GPU-ul nu este responsabil pentru inițială de redare de vedere, dar în schimb este dat texturi, sau bitmap, uneori cu un strat de proprietăți, după ce au fost prestate. Acesta este apoi responsabil pentru compunerea de bitmaps, făcând toate acele strat afectează, și majoritatea de animație (Core Animation).

În cazul de vedere masă de celule, GPU-ul poate fi ieșire cu complex de vedere ierarhii, pentru că în loc de animare un bitmap, este animarea vedere părinte, și de a face subview layout calcule, randare efecte de strat, și compunere toate subviews. Deci, în loc de animare un bitmap, este responsabil pentru relația dintre grămadă de bitmap, și modul în care acestea interacționează, pentru aceeași zonă pixel.

Deci, în rezumat, motivul desen dumneavoastră mobil într-un punct de vedere cu grafică de bază poate accelera de masă defilare NU este pentru că's desen mai repede, ci pentru că este reducerea sarcinii pe GPU, care este gâtuire oferindu-vă probleme în acest scenariu.

Comentarii (1)

Eu sunt un dezvoltator de joc, și am fost pus aceleași întrebări atunci când prietenul meu mi-a spus că-mi UIImageView vedere bazată pe ierarhie a fost de gând să încetinească jocul meu și să-l îngrozitor. Apoi am procedat la cercetarea tot ce am putut găsi despre dacă doriți să utilizați UIViews, CoreGraphics, OpenGL sau ceva 3rd party ca Cocos2D. Consecventă răspuns am primit de la prieteni, profesori, și inginerii Apple la WWDC a fost că nu va't fi mai mult de o diferență în cele din urmă, deoarece la un anumit nivel toate fac același lucru. De nivel superior opțiuni, cum ar fi UIViews se bazează pe nivelul inferior opțiuni, cum ar fi CoreGraphics și OpenGL, doar ele sunt ambalate în cod pentru a face mai ușor pentru tine de a utiliza.

Don't folosi CoreGraphics dacă sunteți doar de gând să sfârșesc re-scrierea UIView. Cu toate acestea, puteți obține unele de viteză de la utilizarea CoreGraphics, atâta timp cât tu faci toate dvs. de desen într-un punct de vedere, dar este într-adevăr valoare a? Răspunsul l-am găsit este, de obicei, nu. Când am început jocul meu, am fost de lucru cu iPhone 3G. Ca jocul meu a crescut în complexitate, am început să văd ceva lag, dar cu dispozitive noi a fost complet neobservat. Acum am o mulțime de acțiune, și numai gal pare a fi o picătură în 1-3 fps cand joc la nivelul cel mai complex de pe un iPhone 4.

Totuși, am decis să utilizeze Instrumente pentru a găsi funcții care au luat cel mai mult timp. Am găsit că problemele nu au fost legate de utilizarea mea de UIViews. În schimb, a fost în mod repetat de asteptare CGRectMake pentru anumite coliziune detectare calcule și încărcarea de imagini și fișiere audio separat pentru anumite clase care folosesc aceleași imagini, mai degrabă decât să le trage de la un depozit central de clasa.

Deci, în final, ați putea fi capabil de a realiza o ușoară obține de la utilizarea CoreGraphics, dar de obicei aceasta nu va fi în valoare de ea sau nu poate avea nici un efect, la toate. Singura dată când am folosi CoreGraphics este atunci când desen forme geometrice, mai degrabă decât text și imagini.

Comentarii (1)