Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction of CXCKeyValueObserver - KVO and Unit Testing

cockscomb
February 15, 2014

Introduction of CXCKeyValueObserver - KVO and Unit Testing

My presentation @ Cocoa Kansai #54, about CXCKeyValueObserver (https://github.com/cockscomb/CXCKeyValueObserver)

cockscomb

February 15, 2014
Tweet

More Decks by cockscomb

Other Decks in Programming

Transcript

  1. CXC

  2. - (void)viewDidLoad { [super viewDidLoad]; [self.someObject addObserver:self forKeyPath:@"example" options:NSKeyValueObservingOptionNew context:NULL];

    } ! - (void)dealloc { [self.someObject removeObserver:self forKeyPath:@"example"]; } ! - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.someObject) { if ([keyPath isEqualToString:@"example"]) { // do something } } }
  3. - (void)viewDidLoad { [super viewDidLoad]; [self.someObject addObserver:self forKeyPath:@"example" options:NSKeyValueObservingOptionNew context:NULL];

    } ! - (void)dealloc { [self.someObject removeObserver:self forKeyPath:@"example"]; } ! - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.someObject) { if ([keyPath isEqualToString:@"example"]) { // do something } } } 1
  4. - (void)viewDidLoad { [super viewDidLoad]; [self.someObject addObserver:self forKeyPath:@"example" options:NSKeyValueObservingOptionNew context:NULL];

    } ! - (void)dealloc { [self.someObject removeObserver:self forKeyPath:@"example"]; } ! - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.someObject) { if ([keyPath isEqualToString:@"example"]) { // do something } } } 1 2
  5. - (void)viewDidLoad { [super viewDidLoad]; [self.someObject addObserver:self forKeyPath:@"example" options:NSKeyValueObservingOptionNew context:NULL];

    } ! - (void)dealloc { [self.someObject removeObserver:self forKeyPath:@"example"]; } ! - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.someObject) { if ([keyPath isEqualToString:@"example"]) { // do something } } } 1 3 2
  6. - (void)viewDidLoad { [super viewDidLoad]; [self.someObject addObserver:self forKeyPath:@"example" options:NSKeyValueObservingOptionNew context:NULL];

    } ! - (void)dealloc { [self.someObject removeObserver:self forKeyPath:@"example"]; } ! - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.someObject) { if ([keyPath isEqualToString:@"example"]) { // do something } } }
  7. - (void)viewDidLoad { [super viewDidLoad]; _observer = [[CXCKeyValueObserver alloc] initWithObservee:self.someObject

    forKeyPath:@"example" options:NSKeyValueObservingOptionNew block:^(id observee, NSString *keyPath, NSDictionary *change) { // do something }]; }
  8. Unit Testing Tools • XCTest • (BDDϥΠϒϥϦ) • ඇಉظςετϥΠϒϥϦ •

    ΧελϜϚονϟ • Mock/StubϥΠϒϥϦ • ωοτϫʔΫstubϥΠϒϥϦ
  9. ඇಉظςετ • ϥΠϒϥϦ • Kiwi • Specta • TRVSMonitor •

    TKRGuard • ಉظతʹॲཧ͞Εͳ͍ͱ͖ͷςετ
  10. • BDD • Kiwi • Specta • ඇಉظςετ • Kiwi

    • Specta • TRVSMonitor • TKRGuard ! • ΧελϜϚονϟ • Kiwi • OCHamcrest • Expecta • Mock/Stub • Kiwi • OCMock • ωοτϫʔΫstub • Nocilla • OHHTTPStubs
  11. @interface CXCKeyValueObserverTestsObject : NSObject @property (nonatomic, strong) id exampleProperty; @end

    @implementation CXCKeyValueObserverTestsObject @end ! SpecBegin(CXCKeyValueObserver) describe(@"KeyValueObserver", ^{ ! __block CXCKeyValueObservingBlock block; __block id gotObservee; __block NSString *gotKeyPath; __block NSDictionary *gotChange; __block CXCKeyValueObserverTestsObject *observee; __block NSString *keyPath; ! beforeEach(^{ block = ^(id _observee, NSString *_keyPath, NSDictionary *_change) { gotObservee = _observee; gotKeyPath = _keyPath; gotChange = _change; }; gotObservee = nil; gotKeyPath = nil; gotChange = nil; observee = [[CXCKeyValueObserverTestsObject alloc] init]; keyPath = NSStringFromSelector(@selector(exampleProperty)); }); ! ... }); SpecEnd
  12. it(@"should call its block when the observing property changed", ^{

    __unused CXCKeyValueObserver *observer = [[CXCKeyValueObserver alloc] initWithObservee:observee forKeyPath:keyPath options:0 block:block]; ! observee.exampleProperty = @"exampleNewValue"; ! expect(gotObservee).to.equal(observee); expect(gotKeyPath).to.beIdenticalTo(keyPath); expect(gotChange).notTo.beNil(); });
  13. it(@"should call removeObserver:forKayPath:context: when deallocated", ^{ id mock = [OCMockObject

    niceMockForClass: [CXCKeyValueObserverTestsObject class]]; [[mock expect] removeObserver:[OCMArg any] forKeyPath:keyPath context:[OCMArg anyPointer]]; ! @autoreleasepool { CXCKeyValueObserver *observer = [[CXCKeyValueObserver alloc] initWithObservee:mock forKeyPath:keyPath options:0 block:block]; ! observer = nil; } ! [mock verify]; });
  14. description - (NSString *)description { NSMutableString *description = [NSMutableString stringWithFormat:@"<%@:

    ", NSStringFromClass([self class])]; [description appendFormat:@"self.observee=%@", self.observee]; [description appendFormat:@", self.keyPath=%@", self.keyPath]; [description appendFormat:@", self.options=%lu", (unsigned long)self.options]; [description appendFormat:@", self.block=%p", self.block]; [description appendString:@">"]; return description; }