Om du någonsin har arbetat med KVO (Key-Value Observing) i Kakao är chansen att du har stött på olika typer av problem. API: n är inte bra och att glömma att ta bort en observatör kan leda till minnesläckor eller - ännu värre kraschar. Facebook: s KVOController-bibliotek syftar till att lösa detta problem.
Om du är ny för att följa viktiga värden eller KVO rekommenderar jag att du först läser Apples utvecklarguide om ämnet eller Mattt Thompson's artikel om NSHipster. För att citera Apples guide på KVO, "Observation av viktiga värden ger en mekanism som gör att objekt kan anmälas om ändringar i specifika egenskaper hos andra objekt." Mattt definierar KVO enligt följande: "Key-Value Observing möjliggör ad hoc, händelseintrospektering mellan specifika objekt instanser genom att lyssna på förändringar på en viss nyckelväg." Nyckelorden är evented och nyckelväg.
Innan vi diskuterar biblioteket KVOController vill jag ta en stund att utforska KVO API.
Jag kommer inte att täcka KVO i detalj i den här handledningen, men det är viktigt att du förstår KVOs kärnkoncept. Tanken är enkel. Ett objekt kan lyssna på ändringar i specifika egenskaper hos ett annat objekt. Observeringsobjektet läggs till av målobjektet som en observatör för en specifik nyckelväg.
Låt oss illustrera detta med ett exempel. Om objectB
önskar bli underrättad när namn
egendom av Objecta
ändras då Objecta
behöver lägga till objectB
som observatör för nyckelvägen namn
. Tack vare Objective-Cs verbositet är koden för att uppnå detta ganska enkelt.
[objectA addObserver: objectB forKeyPath: @ "name" alternativ: NSKeyValueObservingOptionNew context: NULL];
Närhelst Objecta
's namn
egendomsförändringar, observeValueForKeyPath: ofObject: change: sammanhang:
åberopas. Den första parametern är den nyckelväg som observeras av objectB
, den andra parametern är objektet för nyckelbanan, det tredje argumentet är en ordbok som beskriver ändringarna, och det sista argumentet är det sammanhang som passades som det sista argumentet om addObserver: forKeyPath: alternativ: sammanhang:
.
Jag hoppas att du håller med om att detta inte är så elegantt. Om du använder en omfattande användning av KVO, genomförandet av observeValueForKeyPath: ofObject: change: context: snabbt blir lång och komplex.
Det är viktigt att sluta lyssna på ändringar när ett objekt inte längre är intresserad av att ta emot meddelanden för en specifik nyckelväg. Detta görs genom att åberopa removeObserver: forKeyPath:
eller removeObserver: forKeyPath: sammanhang:
.
Frågan som varje utvecklare går in på vid något tillfälle är antingen att glömma att ringa removeObserver: forKeyPath:
eller ringa removeObserver: forKeyPath:
med en nyckelväg som inte observeras av observatören. Anledningen till detta är många gånger och är grunden till det problem som många utvecklare står inför när de arbetar med KVO.
Om du glömmer att anropa removeObserver: forKeyPath:
, du kan sluta med en minnesläcka. Om du åberopar removeObserver: forKeyPath:
och objektet är inte registrerat som observatör ett undantag kastas. Körsbären på kakan är den NSKeyValueObserving
protokollet ger inte ett sätt att kontrollera om ett objekt observerar en viss nyckelväg.
Lyckligtvis var kakao laget på Facebook lika irriterad av ovanstående problem som du är och de kom fram till en lösning, KVOController biblioteket. I stället för att återuppfinna hjulet bestämde laget på Facebook att bygga på toppen av KVO. Trots sina brister är KVO robust, brett stödjande och mycket användbar.
KVOController-biblioteket lägger till ett antal saker till KVO:
Innan vi börjar, är det viktigt att betona att KVOController-biblioteket kräver ARC och att minsta implementeringsmål är iOS 6 för iOS och 10,7 för OS X.
Jag är en stor förespråkare för CocoaPods och jag hoppas att du är också. För att lägga till KVOController-biblioteket till ett projekt med CocoaPods, lägg till podgen till ditt projekts Podfile och kör pod uppdatering
för att installera biblioteket.
pod 'KVOController'
Alternativt kan du hämta den senaste versionen av biblioteket från GitHub och manuellt lägga till biblioteket genom att kopiera KVOController.h och KVOController.m till ditt projekt.
Det första du behöver göra är att initiera en instans av FBKVOController
klass. Ta en titt på följande kodstämpel där jag skapar en FBKVOController
instans i en kontroller initWithNibName: bunt:
metod.
- (id) initWithNibName: (NSString *) nibNameOrNil bunt: (NSBundle *) nibBundleOrNil self = [super initWithNibName: nibNameOrNil bunt: nibBundleOrNil]; om (själv) _KVOController = [FBKVOControllercontrollerWithObserver: self]; återvänd själv
Observera att jag lagrar en referens till FBKVOController
objekt i visningsregulatorens _KVOController
instansvariabel. En stor funktion i KVOController biblioteket är att observatören automatiskt tas bort det ögonblick som FBKVOController
objektet fördelas. Med andra ord, det finns inget behov av att komma ihåg att ta bort observatören eftersom det görs automatiskt när ögonblicket FBKVOController
objektet fördelas.
Du har flera alternativ att börja observera ett objekt. Du kan ta det traditionella tillvägagångssättet genom att åberopa observera: nyckelsökväg: alternativ: sammanhang:
. Resultatet är det observeValueForKeyPath: ofObject: change: sammanhang:
åberopas när en förändringshändelse äger rum.
[_KVOController observera: person nyckelPath: @ "namn" alternativ: NSKeyValueObservingOptionNew context: NULL];
Men FBKVOController
klassen utnyttjar också block och anpassade åtgärder som du kan se i följande kodfragment. Jag är säker på att du håller med om att det här gör att KVO är mycket roligare.
[_KVOController observera: person nyckelPath: @ "namn" alternativ: NSKeyValueObservingOptionNew block: ^ (id observer, id objekt, NSDictionary * ändra) // svara på ändringar];
[_KVOController observera: person nyckelPath: @ "namn" alternativ: NSKeyValueObservingOptionNew action: @selector (nameDidChange :)];
Även om observatören avlägsnas automatiskt när FBKVOController
objektet fördelas, är det ofta nödvändigt att sluta observera ett objekt innan observatören avdelas. KVOController-biblioteket har ett antal metoder för att uppnå denna enkla uppgift.
För att sluta observera en specifik nyckelväg för ett objekt, åberopa unobserve: nyckelsökväg:
och passera objektet och nyckelbanan. Du kan också sluta observera ett objekt genom att åberopa unobserve:
och passera i objektet du vill sluta observera. För att sluta observera varje objekt kan du skicka FBKVOController
objekt ett meddelande om unobserveAll
.
Om du tittar på implementeringen av FBKVOController
klass märker du att den håller en inre karta över objekten och nyckelbanorna som observatören observerar. De FBKVOController
klassen är mer förlåtande än Apples genomförande av KVO. Om du säger till FBKVOController
föremål för att sluta observera ett objekt eller en nyckelväg som den inte observerar, kastas inget undantag. Så ska det vara.
Även om KVO inte är ett svårt begrepp att förstå, se till att observatörer avlägsnas ordentligt och att rasförhållanden inte orsakar kaos är den verkliga utmaningen när man arbetar med KVO.
Jag uppmanar dig att ta en titt på KVOController-biblioteket. Jag rekommenderar dock dig också att få en god förståelse för KVO innan du använder den i dina projekt så att du vet vad det här biblioteket gör för dig bakom kulisserna.