Hvis du noen gang har jobbet med KVO (Key-Value Observing) i Kakao, er det sjansen for at du har gått inn i ulike typer problemer. API-en er ikke stor, og glemmer å fjerne en observatør kan føre til hukommelse lekkasje eller enda verre-krasjer. Facebooks KVOController-bibliotek tar sikte på å løse dette problemet.
Hvis du er ny for nøkkelverdier eller KVO, anbefaler jeg at du først leser Apples utviklerveiledning om emnet eller Mattt Thompsons artikkel om NSHipster. For å sitere Apples veiledning på KVO, inneholder "Key-value observing" en mekanisme som lar objekter bli varslet om endringer i bestemte egenskaper til andre objekter. " Mattt definerer KVO som følger, "Nøkkelverdiobservasjon tillater ad hoc, evented introspeksjon mellom bestemte objektinstanser ved å lytte etter endringer på en bestemt nøkkelbane." Søkeordene er evented og nøkkelbane.
Før vi diskuterer KVOController-biblioteket, vil jeg gjerne ta et øyeblikk for å utforske KVO API.
Jeg vil ikke dekke KVO i detalj i denne opplæringen, men det er viktig at du forstår kjernekonseptet til KVO. Ideen er enkel. Et objekt kan lytte til endringer i bestemte egenskaper til et annet objekt. Observeringsobjektet legges til av målobjektet som en observatør for en bestemt nøkkelbane.
La oss illustrere dette med et eksempel. Hvis objectB
Ønsker å bli varslet når Navn
tilhører Objecta
endrer seg da Objecta
må legge til objectB
som observatør for nøkkelbanen Navn
. Takket være Objective-Cs verbositet er koden for å oppnå dette ganske enkelt.
[objectA addObserver: objectB forKeyPath: @ "name" alternativer: NSKeyValueObservingOptionNew kontekst: NULL];
Når som helst Objecta
's Navn
eiendomsendringer, observeValueForKeyPath: ofObject: endring: kontekst:
er påkalt. Den første parameteren er nøkkelbanen som observeres av objectB
, Den andre parameteren er objektet til nøkkelbanen, det tredje argumentet er en ordbok som beskriver endringene, og det endelige argumentet er konteksten som ble bestått som det endelige argumentet om addObserver: forKeyPath: alternativer: kontekst:
.
Jeg håper du er enig i at dette ikke er veldig elegant. Hvis du bruker omfattende bruk av KVO, implementeres observeValueForKeyPath: ofObject: change: kontekst: blir raskt lang og kompleks.
Det er viktig å slutte å lytte etter endringer når et objekt ikke lenger er interessert i å motta varsler for en bestemt nøkkelbane. Dette gjøres ved å påkalle removeObserver: forKeyPath:
eller removeObserver: forKeyPath: kontekst:
.
Problemet som hver utvikler går inn i på et tidspunkt, er enten å glemme å ringe removeObserver: forKeyPath:
eller ringe removeObserver: forKeyPath:
med en nøkkelbane som ikke observeres av observatøren. Årsakene til dette er mangefold og er roten til problemet mange utviklere møter når de jobber med KVO.
Hvis du glemmer å påkalle removeObserver: forKeyPath:
, Du kan ende opp med et minnelekkasje. Hvis du påberoper removeObserver: forKeyPath:
og objektet er ikke registrert som observatør et unntak kastes. Kirsebær på kaken er at NSKeyValueObserving
protokollen gir ikke en måte å kontrollere om et objekt observerer en bestemt nøkkelbane.
Heldigvis var kakaolaget på Facebook like irritert av de ovennevnte problemene som du er, og de kom opp med en løsning, KVOController-biblioteket. I stedet for å gjenoppfinne hjulet bestemte teamet på Facebook å bygge på toppen av KVO. Til tross for manglene er KVO robust, støttet og støttet.
KVOController biblioteket legger til en rekke ting til KVO:
Før vi kommer i gang, er det viktig å understreke at KVOController-biblioteket krever ARC, og at de minste distribusjonsmålene er iOS 6 for iOS og 10.7 for OS X.
Jeg er en stor forutsetning for CocoaPods, og jeg håper du er også. For å legge til KVOController-biblioteket til et prosjekt som bruker CocoaPods, legg til podet til prosjektets Podfile og løp pod oppdatering
å installere biblioteket.
pod 'KVOController'
Alternativt kan du laste ned den nyeste versjonen av biblioteket fra GitHub og manuelt legge til biblioteket ved å kopiere KVOController.h og KVOController.m til prosjektet ditt.
Det første du må gjøre er å initialisere en forekomst av FBKVOController
klasse. Ta en titt på følgende kodestykke der jeg oppretter en FBKVOController
forekomst i en visningskontrollant initWithNibName: bundle:
metode.
- (id) initWithNibName: (NSString *) nibNameOrNil bundle: (NSBundle *) nibBundleOrNil self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil]; hvis (selv) _KVOController = [FBKVOController controllerWithObserver: self]; returner selv;
Legg merke til at jeg lagrer en referanse til FBKVOController
objekt i visningsregulatorens _KVOController
instansvariabel. En flott funksjon av KVOController-biblioteket er at observatøren automatisk fjernes øyeblikket FBKVOController
objektet deles ut. Med andre ord, det er ikke nødvendig å huske å fjerne observatøren da dette gjøres automatisk i øyeblikket FBKVOController
objektet deles ut.
Du har flere alternativer for å begynne å observere et objekt. Du kan ta den tradisjonelle tilnærmingen ved å påkalle observere: Nøkkelbanen: alternativer: kontekst:
. Resultatet er det observeValueForKeyPath: ofObject: endring: kontekst:
påberopes når en endringshendelse finner sted.
[_KVOController observere: person keyPath: @ "navn" alternativer: NSKeyValueObservingOptionNew kontekst: NULL];
Imidlertid FBKVOController
klassen utnytter også blokker og tilpassede handlinger som du ser i følgende kodestykker. Jeg er sikker på at du er enig i at dette gjør jobben med KVO mye morsommere.
[_KVOController observere: person nøkkelPath: @ "navn" alternativer: NSKeyValueObservingOptionNy blokk: ^ (id observatør, id objekt, NSDictionary * endre) // Svar på endringer];
[_KVOController observere: person keyPath: @ "navn" alternativer: NSKeyValueObservingOptionNew action: @selector (nameDidChange :)];
Selv om observatøren automatisk blir fjernet når FBKVOController
Objektet er avsatt, det er ofte nødvendig å slutte å observere et objekt før observatøren blir hendelt. KVOController-biblioteket har en rekke metoder for å oppnå denne enkle oppgaven.
For å stoppe å observere en bestemt nøkkelbane for et objekt, påkalle unobserve: Nøkkelbanen:
og pass objektet og nøkkelbanen. Du kan også slutte å observere et objekt ved å påkalle unobserve:
og passere i objektet du vil slutte å observere. For å stoppe å observere hvert objekt, kan du sende FBKVOController
motta en melding av unobserveAll
.
Hvis du ser på implementeringen av FBKVOController
klassen, vil du legge merke til at den holder et internt kart over objekter og nøkkelbaner observatøren observerer. De FBKVOController
Klassen er mer tilgivende enn Apples implementering av KVO. Hvis du forteller FBKVOController
gjenstand for å slutte å observere et objekt eller en nøkkelbane som den ikke observerer, blir ikke noe unntak kastet. Slik skal det være.
Selv om KVO ikke er et vanskelig konsept å forstå, må du sørge for at observatører blir fjernet og løpevilkårene ikke forårsaker kaos, er den virkelige utfordringen når du jobber med KVO.
Jeg oppfordrer deg til å ta en titt på KVOController-biblioteket. Men jeg anbefaler deg også å få en god forståelse av KVO før du bruker den i prosjektene dine, slik at du vet hva dette biblioteket gjør for deg bak kulissene.