Slide 1

Slide 1 text

cockscomb

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

͸ͯͳϒϩά

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

CXC

Slide 7

Slide 7 text

CXCKeyValueObserver

Slide 8

Slide 8 text

Key Value Observation

Slide 9

Slide 9 text

Key Value Observation • Key Value CodingͰΦϒδΣΫτͷঢ়ଶΛ؂ࢹ • @property͸KVCͷنଇʹै͏ͨΊ؂ࢹͰ͖Δ • Modelͷঢ়ଶΛ؂ࢹͯ͠ViewΛߋ৽ͳͲͰศར

Slide 10

Slide 10 text

- (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 } } }

Slide 11

Slide 11 text

- (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

Slide 12

Slide 12 text

- (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

Slide 13

Slide 13 text

- (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

Slide 14

Slide 14 text

- (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 } } }

Slide 15

Slide 15 text

• observeValueForKeyPath:ofObject:change:context:
 ͱ͍͏ϝιουʹશͯهड़͠ͳ͚Ε͹ͳΒͳ͍ • removeObserver:forKeyPath:
 Λݺͼ๨Εͯ͸͍͚ͳ͍ • ͩΜͩΜෳࡶʹͳ͍ͬͯ͘ • ෳ਺ਓ։ൃʹ޲͔ͳ͍આ

Slide 16

Slide 16 text

CXCKeyValueObserver

Slide 17

Slide 17 text

- (void)viewDidLoad { [super viewDidLoad]; _observer = [[CXCKeyValueObserver alloc] initWithObservee:self.someObject forKeyPath:@"example" options:NSKeyValueObservingOptionNew block:^(id observee, NSString *keyPath, NSDictionary *change) { // do something }]; }

Slide 18

Slide 18 text

• BlockΛ༻͍ͯએݴతʹهड़ • observer΁ͷڧࢀর͕ͳ͘ͳΔͱ͖ࣗಈతʹ
 removeObserver:forKeyPath: • ϦʔζφϒϧͳΠϯλʔϑΣʔε

Slide 19

Slide 19 text

https://github.com/cockscomb/CXCKeyValueObserver

Slide 20

Slide 20 text

CXCKeyValueObserver • MIT License • CocoaPodsରԠ • ୯ମςετ

Slide 21

Slide 21 text

˒14

Slide 22

Slide 22 text

Unit Test

Slide 23

Slide 23 text

The Unit Testing of Objective-C • https://speakerdeck.com/cockscomb/the- unit-testing-of-objective-c • Kiwi • Nocilla

Slide 24

Slide 24 text

Unit Testing Tools • XCTest • (BDDϥΠϒϥϦ) • ඇಉظςετϥΠϒϥϦ • ΧελϜϚονϟ • Mock/StubϥΠϒϥϦ • ωοτϫʔΫstubϥΠϒϥϦ

Slide 25

Slide 25 text

XCTest

Slide 26

Slide 26 text

BDD • ϥΠϒϥϦ • Kiwi • Specta • Behavior Driven Development

Slide 27

Slide 27 text

ඇಉظςετ • ϥΠϒϥϦ • Kiwi • Specta • TRVSMonitor • TKRGuard • ಉظతʹॲཧ͞Εͳ͍ͱ͖ͷςετ

Slide 28

Slide 28 text

ΧελϜϚονϟ • ϥΠϒϥϦ • Kiwi • OCHamcrest • Expecta • ศརͳAssert

Slide 29

Slide 29 text

Mock/Stub • ϥΠϒϥϦ • Kiwi • OCMock • ςετ͍ͨ͠ΦϒδΣΫτͷؔ࿈ΦϒδΣΫτ Λٖࣅతʹ࡞Γग़ͯ͠ςετΛ؆ུԽ

Slide 30

Slide 30 text

ωοτϫʔΫStub • ϥΠϒϥϦ • Nocilla • OHHTTPStubs • ωοτϫʔΫͷঢ়ଶ΍ϨεϙϯεΛٖࣅతʹ࡞ Γग़ͯ͠ωοτϫʔΫपΓͷςετΛ؆ུԽ

Slide 31

Slide 31 text

• BDD • Kiwi • Specta • ඇಉظςετ • Kiwi • Specta • TRVSMonitor • TKRGuard ! • ΧελϜϚονϟ • Kiwi • OCHamcrest • Expecta • Mock/Stub • Kiwi • OCMock • ωοτϫʔΫstub • Nocilla • OHHTTPStubs

Slide 32

Slide 32 text

CXCKeyValueObserver • Specta • Expecta • OCMock

Slide 33

Slide 33 text

@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

Slide 34

Slide 34 text

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(); });

Slide 35

Slide 35 text

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]; });

Slide 36

Slide 36 text

CXCKeyValueObserver • Specta • Expecta • OCMock

Slide 37

Slide 37 text

ࡶஊίʔφʔ

Slide 38

Slide 38 text

description • descriptionॻ͍͓͖͍ͯͨ • ඞཁʹԠͯ͡debugDescription • AppCodeศར

Slide 39

Slide 39 text

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; }

Slide 40

Slide 40 text

AppCode

Slide 41

Slide 41 text

AppCode • JetBrains IDE • ௒ߴػೳ

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

AppCode • ݡ͍ΦʔτίϯϓϦʔτ • ϦϑΥʔϚοτ • ίʔυͷੜ੒ • ϦϑΝΫλϦϯά • ίʔυͷղੳ

Slide 46

Slide 46 text

github.com/cockscomb/CXCKeyValueObserver

Slide 47

Slide 47 text

DPDLTDPNCIBUFOBCMPHDPN