Aspect OrientedProgramming楊維中 a.k.a zonble[email protected]Thursday, September 12,
View Slide
zonbleฌᖯ؛ۇThursday, September 12,
ᖯ৵ʔ݊ɓ˂ிϓٙUnmaintainable 的 code 也是Thursday, September 12,
⼀一開始,程式邏輯就只有插⼊入資料⽽而已…- (void)appendData:(NSData *)inData { [_data appendData:inData];}Thursday, September 12,
後來,我們想確定傳⼊入的不是 nil 或空資料- (void)appendData:(NSData *)inData { NSParameterAssert(inData != nil); NSParameterAssert([inData length]); length = [_data length]; [_data appendData:inData]; NSAssert(length != [_data length]);}Thursday, September 12,
後來,我們覺得 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,
後來,我們發現這個 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,
後來,在 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,
Release Build 則要加上 FlurryEvent 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,
還有 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,
每件事情都很重要• 確定傳⼊入參數的型態與內容• 確定真的有插⼊入資料• 加 Lock• 加 Debug Log• 加 TestFlight Log、Flurry Log…Thursday, September 12,
23 ⾏行 code 中,ਂ͍ԫ̥ٙϞɓБf這還不是最糟的…Thursday, September 12,
更糟的是…不只⼀一個 method 這樣Thursday, September 12,
ᒔึॎᕸόٙࠠ͜Thursday, September 12,
上個世紀末,就有⼈人覺得…வᅵʔБ接下來的故事請⾃自⼰己查 WikipediaThursday, September 12,
AOP 的基本想法:Ҫ၇ౢආԸٙCode פᕎԨ܆ༀ⽅方法很多Thursday, September 12,
Cross-cutting concerns…就是這些• 確定傳⼊入參數的型態與內容• 確定真的有插⼊入資料• 加 Lock• 加 Debug Log• 加 TestFlight Log、Flurry Log…Thursday, September 12,
Advice在原本程式前後插⼊入的程式碼Thursday, September 12,
DecoratorSyntax…Objective C 不⽀支援Thursday, September 12,
Decorator Syntaxdef add(x): print "x:" + str(x) result = x + 1 print "result:" + str(result) return resultThursday, September 12,
Decorator Syntaxdef log(func): def inner_func(*a): print "args:" + str(a) result = func(*a) print "result:" + str(result) return inner_func@logdef add(x): return x + 1Thursday, September 12,
Objective-C 特性MessageForwarding當⼀一個物件不⽀支援某個 Selector 的時候,這個物件可以決定把 Selector 交給其他的物件。Thursday, September 12,
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 GuideThursday, September 12,
AOP-in-Objective-Chttps://github.com/moszi/AOP-in-Objective-CThursday, September 12,
MethodSwizzlingThursday, September 12,
Objective-C 第⼀一課• ObjC 物件都是 C Structure• ObjC method 都是 C function pointer• 系統有⼀一個動態的索引表格,決定執⾏行某個 selector 時,要對應到哪個 Cfunction• Selector 就是索引表中的 key,型態為 C字串Thursday, September 12,
Objective-C 第⼆二課• ⼀一個 Class 有哪些 method,都是在runtime 的時候建⽴立的• 所以可以在 runtime 新增新的 method,例如使⽤用 category 語法• 也可以直接使⽤用 runtime API 把已經存在的 method 換掉Thursday, September 12,
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);IMP method_setImplementation(Method method, IMP imp);Thursday, September 12,
Thursday, September 12,
AOP-for-Objective-Chttps://github.com/ndcube/AOP-for-Objective-C/在繼承關係的部份有些 bug,我⾃自⼰己有先修,但是還沒有送 pull request…Thursday, September 12,
Thank you!Thursday, September 12,