scris de Reinder de Vries pe 10 ianuarie 2019 în dezvoltarea aplicațiilor, Swift

un singleton este o clasă din care există exact o instanță, care poate fi accesată la nivel global. Cum creezi un singleton în Swift? Și de ce ar trebui sau nu ar trebui?

în acest tutorial, vom arunca cu capul în singletons în Swift. Aflați ce este modelul de design singleton și de ce este util. Vom discuta sintaxa pentru crearea singletons în Swift. Și vom intra în cazuri bune și rele de utilizare pentru singletons.

gata? Să mergem.

  1. Ce Este Un Singleton?
  2. Codificarea Unui Singleton În Swift
  3. Când Se Utilizează Singleton
  4. Lecturi Suplimentare

Ce Este Un Singleton?

un singleton este o clasă din care există o singură instanță. Câteva exemple:

  • o companie are un singur CEO
  • o clasă API are doar o singură coadă de solicitare serială
  • un sistem de operare are un singur sistem de fișiere
  • un corp al sistemului solar se învârte în jurul unui punct gravitațional
  • o aplicație care face I/O are un singur implicit FileManager
  • un avion are o singură punte de zbor

al doilea atribut al unui Singleton este că are un punct global de acces. Puteți accesa un singleton, de ex. funcții de apel pe ea, de oriunde în codul aplicației.

deci, pentru a rezuma:

  1. un singleton este o clasă care are o singură instanță
  2. poate fi accesat la nivel global, adică oriunde în codul dvs.

în dezvoltarea practică a iOS, utilizați singletons des. Clase tipice cum ar fi NotificationCenter, UserDefaults, SKPaymentQueue și FileManager au shared sau default proprietăți care sunt singletons.

în alte momente, ați putea dori să creați singur un singleton. Un caz bun de utilizare este o clasă API care expune instanța singleton prin proprietatea sa shared. Utilizați API.shared.makeAPICall() pentru a accesa API – ul printr-o singură instanță unificată. Acest lucru vă permite, de exemplu, să gestionați apelurile API în serie.

înainte de a discuta când singletonii sunt cel mai bine folosiți (și când nu), să aflăm cum să codificăm un singleton în Swift.

angajați-vă ca dezvoltator iOS

Aflați cum să construiți Aplicații iOS 14 cu Swift 5

Înscrieți-vă la cursul meu de dezvoltare iOS și aflați cum să vă începeți cariera ca dezvoltator iOS profesionist.

codificarea unui Singleton în Swift

acesta este cel mai bun mod de a crea un singleton în Swift:

class API{ static let shared = API() private init() { // Set up API instance }}

și iată cum utilizați singleton:

API.shared.doSomething()

creăm o clasă API care are o proprietate statică numită shared. Această proprietate nu poate fi modificată odată setată, deoarece este o constantă și este declarată static.

asta înseamnă că putem accesa proprietatea sharedprin clasa API. Aceasta este adesea numită proprietate de clasă. Comparați acest lucru cu o proprietate de instanță normală, care poate fi accesată numai printr-o instanță a unei clase.

ceea ce este interesant este că proprietatea shared inițializează o instanță de API în clasa API. Creăm un obiect API care poate fi accesat prin clasa API. Dar există mai multe…

inițializatorul de clasă init() este marcat cu private. Acest cuvânt cheie private asigură că clasa API poate fi inițializată numai în clasa API.

cu alte cuvinte, nu puteți crea o instanță de API în afara clasei API! Acest lucru asigură că obiectul API pe care l-am creat este singura instanță din Codul nostru. La urma urmei, nu poți crea mai mult din ea.

și acum ne-am asigurat API clasa este conformă cu cele două atribute ale unui singleton:

  1. datorită proprietății statice shared, instanța API poate fi accesată la nivel global
  2. datorită private init(), clasa API nu poate fi inițializată în afara clasei API

toate acestea vă pot suna puțin abstract, așa că haideți să extindem exemplul anterior cu un cod mai practic. Iată ce:

clasa API este în mare parte aceeași. Este încă un singleton, și încă folosește acele static let shared = API() și private init() biți de cod.

Iată ce s-a schimbat:

  • clasa API are acum o proprietate isRequestPending. Acest lucru este în cazul în care pericolul începe… vezi cum isRequestPending Boolean asigură că doar o singură cerere API se poate face la un moment dat? (Rețineți că isRequestPending este o proprietate instanță.)
  • clasa API are, de asemenea, o funcție makeAPIRequest(). Imaginați-vă că putem folosi această funcție pentru a obține unele date înapoi de la un API webservice, cum ar fi Twitter. în funcție, puteți vedea că o solicitare poate fi făcută numai atunci când nicio altă solicitare nu este în curs.
  • clasa API are, de asemenea, o funcție onReturnAPIRequest(). Această funcție este invocată atunci când cererea API revine, adică datele online au fost descărcate în aplicație. isRequestPending boolean este setat la false din nou, iar datele de solicitare sunt procesate.

și iată cum putem folosi API singleton oriunde în codul nostru:

API.shared.makeAPIRequest()

mai e ceva ce trebuie să discutăm. Clasa API gestionează acum ceva numit stat. Puteți vedea „starea” ca pe un sentiment: ori ești fericit, ori ești trist, ori ești supărat și așa mai departe. Puteți trece de la o stare la alta.

clasa API poate comuta între două stări:

  • o stare în care isRequestPending este false
  • o stare în care isRequestPending este true

după cum veți afla în secțiunea următoare, de stat și singletons poate face tot felul de ravagii pe codul. Gestionarea de stat prost este cel mai mare motiv unic pentru utilizarea abuzivă singleton.

când să utilizați Singletons

când utilizați singletons? Cartea Design Patterns: Elements of refolosibile Object-Oriented Software by the Gang of Four are următoarele de spus. Utilizați modelul singleton atunci când:

  • trebuie să existe exact o instanță a unei clase și trebuie să fie accesibilă clienților dintr-un punct de acces bine cunoscut
  • când singura instanță ar trebui să fie extensibilă prin subclasare, iar Clienții ar trebui să poată utiliza o instanță extinsă fără a-și modifica codul

este complex, dar ceea ce se reduce:

  • utilizați un singleton atunci când codul dvs. nu necesită mai mult de o instanță a unei clase (adică CEO-ul companiei)
  • și când trebuie să fie accesibil de oriunde din codul dvs. (adică., sistemul de fișiere)

un alt caz de utilizare este subclasarea. O variabilă globală din codul dvs. nu poate fi ușor subclasată, deci de aceea utilizați o clasă singleton. În plus, singletons pot fi testate unitar prin utilizarea injecției de dependență. Înlocuiți instanța API cu o instanță APIMock și obțineți capacitatea de a testa apelurile API fără a face cererile reale de rețea.

și când nu folosiți singletons? Pentru a răspunde la această întrebare, va trebui să ne întoarcem la principiul de stat pe care l-am discutat mai devreme.

o capcană comună pentru dezvoltatorii iOS începători este de a gestiona prost starea și dependențele sale. Imaginați-vă că construiți o aplicație care utilizează clasa API cu care am lucrat mai devreme.

de fiecare dată când extindeți clasa API, abordați din ce în ce mai multe proprietăți, cum ar fi:

  • o proprietate userID care ține evidența utilizatorului conectat, odată ce apelul APIlogin() a fost efectuat
  • o proprietate tweets cu date Twitter, odată ce apelulgetTweets() a fost efectuat
  • o proprietate spinner cu unUIActivityIndicatorView pe care îl adăugați la un controler de vizualizare atunci când a început o cerere

la început, acest lucru are mult sens de făcut. La urma urmei, clasa API poate fi accesată oriunde în codul dvs. Deci, în controlerul de vizualizare Tweet puteți utiliza matricea API.shared.tweets, iar în controlerul de setări puteți utiliza userID pentru a spune rapid API-ului ale cărui setări să se schimbe.

din păcate, starea ta este acum peste tot. Clasa API are dependențe la o grămadă de clase care nu sunt legate de responsabilitatea unică a clasei API. Codul tău a devenit un castron de spaghete, toate încurcate. Codul poate funcționa OK, dar este imposibil să se mențină și să se extindă.

să ne uităm la un exemplu. Funcția onReturnAPIRequest() pe care am definit-o mai devreme este pe punctul de a deveni strâns cuplată…

Iată ce avem în vedere:

  • onReturnAPIRequest() se numește atunci când se întoarce o cerere API webservice, adică atunci când datele intră în aplicație. Aceste date trebuie să meargă undeva-un controler de vizualizare Tweet, de exemplu. Cum transmiteți datele de la API către controlerul de vizualizare?
  • o alegere evidentă este de a crea doar o referință la viewController în API clasă. Când datele intră, puteți codifica ceva de genul viewController.tweets = tweetsData. Din păcate, aceasta este o arhitectură slabă, deoarece acum API și controlerul de vizualizare sunt strâns cuplate. Este imposibil (sau greu) să testați unitatea și este posibil să creați probleme atunci când extindeți oricare dintre clase.
  • este mai bine să alegeți un mecanism care să nu cupleze strâns ambele clase. O opțiune ar fi trecerea unei închideri la onReturnAPIRequest(), care este executată la returnarea cererii. Această închidere poate conține apoi cod pentru a gestiona datele primite. O altă opțiune ar fi utilizarea NotificationCenter pentru a transmite datele către controlerul de vizualizare sau pentru a utiliza o clasă Database pentru a gestiona datele.

modelul de design singleton a câștigat unele controverse, pur și simplu pentru că este ușor de abuzat. Când utilizați singletons, fiți atenți la starea și dependențele. Doar pentru că este ușor să ai acces global la stat, nu înseamnă că este o idee bună.

angajați-vă ca dezvoltator iOS

Aflați cum să construiți Aplicații iOS 14 cu Swift 5

Înscrieți-vă la cursul meu de dezvoltare iOS și aflați cum să vă începeți cariera ca dezvoltator iOS profesionist.

lecturi suplimentare

și asta e tot ce este de făcut! Cunoașterea singletons este un obiectiv util, mai ales dacă sunteți interesat de arhitectura aplicațiilor și proiectarea sistemelor.

Lasă un răspuns

Adresa ta de email nu va fi publicată.