Slide 1

Slide 1 text

Aspect Oriented Programming 楊維中 a.k.a zonble [email protected] Thursday, September 12,

Slide 2

Slide 2 text

zonble ฌᖯ؛ۇ Thursday, September 12,

Slide 3

Slide 3 text

ᖯ৵ʔ݊ɓ˂ிϓٙ Unmaintainable 的 code 也是 Thursday, September 12,

Slide 4

Slide 4 text

⼀一開始,程式邏輯就只有插 ⼊入資料⽽而已… - (void)appendData:(NSData *)inData { [_data appendData:inData]; } Thursday, September 12,

Slide 5

Slide 5 text

後來,我們想確定傳⼊入的不 是 nil 或空資料 - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); length = [_data length]; [_data appendData:inData]; NSAssert(length != [_data length]); } Thursday, September 12,

Slide 6

Slide 6 text

後來,我們覺得 Release Build 也應該防⽌止輸⼊入空資料… - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); if (!inData) { return; } if (![inData length]) { return; } length = [_data length]; [_data appendData:inData]; NSAssert(length != [_data length]); } Thursday, September 12,

Slide 7

Slide 7 text

後來,我們發現這個 method 可能會在很多 thread 呼叫… - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); if (!inData) { NSLog(@"inData is nil!"); return; } if (![inData length]) { NSLog(@"Length of inData is 0!"); return; } length = [_data length]; [_lock lock]; [_data appendData:inData]; [_lock unlock]; NSAssert(length != [_data length]); } Thursday, September 12,

Slide 8

Slide 8 text

後來,在 Debug Build 裡頭要 加上 TestFlight CheckPoint - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); if (!inData) { NSLog(@"inData is nil!"); return; } if (![inData length]) { NSLog(@"Length of inData is 0!"); return; } length = [_data length]; [_lock lock]; [_data appendData:inData]; [_lock unlock]; NSAssert(length != [_data length]); #if DEBUG [TestFlight passCheckpoint:@"APPEND_DATA"]; #endif } Thursday, September 12,

Slide 9

Slide 9 text

Release Build 則要加上 Flurry Event Log… - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); if (!inData) { NSLog(@"inData is nil!"); return; } if (![inData length]) { NSLog(@"Length of inData is 0!"); return; } length = [_data length]; [_lock lock]; [_data appendData:inData]; [_lock unlock]; NSAssert(length != [_data length]); #if DEBUG [TestFlight passCheckpoint:@"APPEND_DATA"]; #else [Flurry logEvent:@"APPEND_DATA"]; #endif } Thursday, September 12,

Slide 10

Slide 10 text

還有 Google Analytics… - (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); if (!inData) { NSLog(@"inData is nil!"); return; } if (![inData length]) { NSLog(@"Length of inData is 0!"); return; } length = [_data length]; [_lock lock]; [_data appendData:inData]; [_lock unlock]; NSAssert(length != [_data length]); #if DEBUG [TestFlight passCheckpoint:@"APPEND_DATA"]; #else [Flurry logEvent:@"APPEND_DATA"]; idtracker = [[GAI sharedInstance] defaultTracker]; [tracker send: [[GAIDictionaryBuilder createEventWithCategory:@"data" withAction:@"append" withLabel:@"user_data" withValue:nil] build]]; #endif } Thursday, September 12,

Slide 11

Slide 11 text

每件事情都很重要 • 確定傳⼊入參數的型態與內容 • 確定真的有插⼊入資料 • 加 Lock • 加 Debug Log • 加 TestFlight Log、Flurry Log… Thursday, September 12,

Slide 12

Slide 12 text

23 ⾏行 code 中, ਂ͍ԫ̥ٙϞɓБf 這還不是最糟的… Thursday, September 12,

Slide 13

Slide 13 text

更糟的是… 不只⼀一個 method 這樣 Thursday, September 12,

Slide 14

Slide 14 text

ᒔึॎᕸ೻όٙࠠ͜ Thursday, September 12,

Slide 15

Slide 15 text

上個世紀末,就有⼈人覺得… வᅵʔБ 接下來的故事請⾃自⼰己查 Wikipedia Thursday, September 12,

Slide 16

Slide 16 text

AOP 的基本想法: Ҫ΢၇೷ౢආԸٙ Code פᕎԨ܆ༀ ⽅方法很多 Thursday, September 12,

Slide 17

Slide 17 text

Cross-cutting concerns …就是這些 • 確定傳⼊入參數的型態與內容 • 確定真的有插⼊入資料 • 加 Lock • 加 Debug Log • 加 TestFlight Log、Flurry Log… Thursday, September 12,

Slide 18

Slide 18 text

Advice       在原本程式前後 插⼊入的程式碼 Thursday, September 12,

Slide 19

Slide 19 text

Decorator Syntax …Objective C 不⽀支援 Thursday, September 12,

Slide 20

Slide 20 text

Decorator Syntax def add(x): print "x:" + str(x) result = x + 1 print "result:" + str(result) return result Thursday, September 12,

Slide 21

Slide 21 text

Decorator Syntax def log(func): def inner_func(*a): print "args:" + str(a) result = func(*a) print "result:" + str(result) return inner_func @log def add(x): return x + 1 Thursday, September 12,

Slide 22

Slide 22 text

Objective-C 特性 Message Forwarding 當⼀一個物件不⽀支援某個 Selector 的時 候,這個物件可以決定把 Selector 交給 其他的物件。 Thursday, September 12,

Slide 23

Slide 23 text

Message Forwarding - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([someOtherObject respondsToSelector: [anInvocation selector]]) // Advice here [anInvocation invokeWithTarget:someOtherObject]; // Advice here else [super forwardInvocation:anInvocation]; } See: Objective-C Runtime Programming Guide Thursday, September 12,

Slide 24

Slide 24 text

AOP-in-Objective-C https://github.com/moszi/AOP-in- Objective-C Thursday, September 12,

Slide 25

Slide 25 text

Method Swizzling Thursday, September 12,

Slide 26

Slide 26 text

Objective-C 第⼀一課 • ObjC 物件都是 C Structure • ObjC method 都是 C function pointer • 系統有⼀一個動態的索引表格,決定執⾏行 某個 selector 時,要對應到哪個 C function • Selector 就是索引表中的 key,型態為 C 字串 Thursday, September 12,

Slide 27

Slide 27 text

Objective-C 第⼆二課 • ⼀一個 Class 有哪些 method,都是在 runtime 的時候建⽴立的 • 所以可以在 runtime 新增新的 method, 例如使⽤用 category 語法 • 也可以直接使⽤用 runtime API 把已經存在 的 method 換掉 Thursday, September 12,

Slide 28

Slide 28 text

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); IMP method_setImplementation(Method method, IMP imp); Thursday, September 12,

Slide 29

Slide 29 text

Thursday, September 12,

Slide 30

Slide 30 text

Thursday, September 12,

Slide 31

Slide 31 text

Thursday, September 12,

Slide 32

Slide 32 text

AOP-for-Objective-C https://github.com/ndcube/AOP-for- Objective-C/ 在繼承關係的部份有些 bug,我⾃自⼰己有 先修,但是還沒有送 pull request… Thursday, September 12,

Slide 33

Slide 33 text

Thank you! Thursday, September 12,