Valoarea cheie observând cu KVOController din Facebook

Introducere

Dacă ați lucrat vreodată cu KVO (Key-Value Observing) în Cocoa, este posibil să fiți diferiți în diverse probleme. Aplicația API nu este grozavă și uitarea pentru eliminarea unui observator poate duce la scurgerea memoriei sau chiar la accidentele mai grave. Biblia KVOController a Facebook își propune să rezolve această problemă.

Ce este observarea cheie-valoare?

Dacă sunteți nou la observarea cu valoare cheie sau KVO, vă recomandăm să citiți mai întâi ghidul dezvoltatorului Apple pe această temă sau articolul lui Mattt Thompson despre NSHipster. Pentru a cita ghidul Apple pe KVO, "Observarea valorii cheie oferă un mecanism care permite obiectelor să fie notificate cu privire la modificările anumitor proprietăți ale altor obiecte". Mattt definește KVO după cum urmează: "Key-Value Observing permite introspecția ad-hoc, evented între instanțe specifice de obiecte ascultând pentru modificări pe o anumită cale cheie." Cuvintele cheie sunt evented și calea cheie.

Înainte de a discuta despre biblioteca KVOController, aș dori să fac un moment pentru a explora API-ul KVO.

Adăugarea unui observator

Nu voi acoperi KVO în detaliu în acest tutorial, dar este important să înțelegeți conceptul de bază al KVO. Ideea este simplă. Un obiect poate asculta modificările anumitor proprietăți ale unui alt obiect. Obiectul observator este adăugat de obiectul țintă ca observator pentru o anumită cale de cheie.

Să ilustrăm acest lucru cu un exemplu. Dacă objectB dorește să fie notificat atunci când Nume proprietatea objectA schimbări, atunci objectA trebuie să adăugați objectB ca observator al căii cheie Nume. Datorită verbozității obiectivului C, codul pentru a realiza acest lucru este destul de simplu.

[objectA addObserver: objectB forKeyPath: @ opțiunile "name": NSKeyValueObservingOptionNew context: NULL];

Răspunsul la modificări

Oricând objectA„s Nume schimbări de proprietate, observeValueForKeyPath: ofObject: schimbare: Context: este invocată. Primul parametru este calea cheie care este observată de către objectB, al doilea parametru este obiectul căii cheie, al treilea argument este un dicționar care descrie modificările, iar argumentul final este contextul care a fost trecut ca argument final al addObserver: forKeyPath: opțiuni: Context:.

Sper că sunteți de acord că acest lucru nu este foarte elegant. Dacă utilizați extensiv KVO, implementarea lui observeValueForKeyPath: ofObject: change: context: rapid devine lungă și complexă.

Eliminarea unui observator

Este important să nu mai ascultați modificările atunci când un obiect nu mai este interesat să primească notificări pentru o anumită cale cheie. Acest lucru se face invocând removeObserver: forKeyPath: sau removeObserver: forKeyPath: Context:.

Problema pe care fiecare dezvoltator o întâmpină într-un anumit moment este fie să uiți să suni removeObserver: forKeyPath: sau sunând removeObserver: forKeyPath: cu o cale cheie care nu este observată de către observator. Motivele pentru acest lucru sunt multiple și sunt rădăcina problemei cu care se confruntă mulți dezvoltatori atunci când lucrează cu KVO.

Dacă uitați să invocați removeObserver: forKeyPath:, este posibil să ajungeți la o scurgere de memorie. Dacă invocați removeObserver: forKeyPath: iar obiectul nu este înregistrat ca observator, o excepție este aruncată. Cireșul de pe tort este că NSKeyValueObserving protocolul nu oferă o modalitate de a verifica dacă un obiect observă o anumită cale de cheie.

KVOController la salvare

Din fericire, echipa de cacao de pe Facebook a fost la fel de supărată de problemele de mai sus, așa cum ești și au venit cu o soluție, biblioteca KVOController. În loc să reinventăm roata, echipa de la Facebook a decis să construiască pe partea de sus a KVO. În ciuda neajunsurilor sale, KVO este robustă, susținută pe scară largă și foarte utilă.

Biblioteca KVOController adaugă o serie de lucruri la KVO:

  • fir de siguranță
  • eliminarea nedureroasă a observatorilor
  • suport pentru blocuri și acțiuni personalizate

cerinţe

Înainte de a începe, este important să subliniem că biblioteca KVOController necesită ARC și că țintele minime de implementare sunt iOS 6 pentru iOS și 10.7 pentru OS X.

Instalare

Sunt un mare susținător al CocoaPods și sper că sunteți prea. Pentru a adăuga biblioteca KVOController la un proiect care utilizează CocoaPods, adăugați podul în Podfile-ul proiectului și executați actualizare pod pentru a instala biblioteca.

pod "KVOController"

Alternativ, puteți descărca ultima versiune a bibliotecii de la GitHub și adăugați manual biblioteca prin copiere KVOController.h și KVOController.m la proiectul dvs..

Exemple

Inițializarea

Primul lucru pe care trebuie să-l faceți este să inițializați o instanță a FBKVOController clasă. Uitați-vă la următorul fragment de cod în care creez a FBKVOController instanță într-un controler de vizualizare initWithNibName: pachet: metodă.

- (id) initWithNibName: (NSString *) pachet nibNameOrNil: (NSBundle *) nibBundleOrNil auto = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil]; dacă (auto) _KVOController = [FBKVOControllerler controllerWithObserver: self];  întoarce-te; 

Rețineți că stochez o referință la FBKVOController obiect în controlerul de vizualizare _KVOController variabila de instanta. O caracteristică excelentă a bibliotecii KVOController este aceea că observatorul este înlăturat automat în momentul în care acesta este FBKVOController obiect este dealocat. Cu alte cuvinte, nu este nevoie să vă amintiți să eliminați observatorul, deoarece acest lucru se face automat în momentul în care se află FBKVOController obiect este dealocat.

Adăugarea unui observator

Aveți mai multe opțiuni pentru a începe observarea unui obiect. Puteți lua abordarea tradițională invocând observa: keyPath: opțiuni: Context:. Rezultatul este că observeValueForKeyPath: ofObject: schimbare: Context: este invocată ori de câte ori are loc un eveniment de schimbare.

[_KVOController observați: keykeyPath: @ opțiuni "name": NSKeyValueObservingOptionNew context: NULL];

Însă FBKVOController clasa utilizează de asemenea blocuri și acțiuni personalizate, după cum puteți vedea în următoarele fragmente de cod. Sunt sigur că sunteți de acord că acest lucru face ca lucrul cu KVO să fie mult mai plăcut.

[_KVOController observați: keykeyPath: @ opțiuni "name": NSKeyValueObservingOptionNew bloc: ^ (obser id, id id, NSDictionary * change) // Răspundeți la modificări];
[_KVOController observați: tasta persoanePath: @ opțiunile "nume": NSKeyValueObservingOptionNew action: @selector (nameDidChange :)];

Eliminarea unui observator

Chiar dacă observatorul este eliminat automat atunci când FBKVOController obiect este dealocat, adesea este necesar să opriți observarea unui obiect înainte de a fi alocat observatorul. Biblioteca KVOController are o serie de metode pentru a îndeplini această sarcină simplă.

Pentru a opri observarea unei anumite căi cheie a unui obiect, invoca unobserve: keyPath: și să treacă obiectul și calea cheie. De asemenea, puteți opri observarea unui obiect invocând unobserve: și treci în obiectul pe care vrei să-l oprești observând. Pentru a opri observarea fiecărui obiect, îl puteți trimite FBKVOController obiectează un mesaj de unobserveAll.

Fara exceptii

Dacă analizați implementarea FBKVOController , veți observa că păstrează o hartă internă a obiectelor și a căilor cheie observate de observator. FBKVOController clasa este mai iertator decât punerea în aplicare a Apple de KVO. Dacă spuneți FBKVOController obiect de a opri observarea unui obiect sau a unei căi cheie pe care nu o observă, nu este aruncată nicio excepție. Așa ar trebui să fie.

Concluzie

Chiar dacă KVO nu este un concept dificil de înțeles, asigurându-vă că observatorii sunt îndepărtați în mod corespunzător și condițiile de rasă nu provoacă haos este adevărata provocare atunci când lucrați cu KVO.

Vă încurajez să aruncați o privire la biblioteca KVOController. Cu toate acestea, vă sfătuiesc să obțineți o bună înțelegere a KVO înainte de ao utiliza în proiectele dvs., astfel încât să știți ce face această bibliotecă pentru dvs. în spatele scenei.

Cod