Method Swizzling

Transcription

Method Swizzling
Method Swizzling
The good, the bad and the ugly
Some background
1.  The Objec,ve-­‐C message model •  You are not calling func,ons, you are passing messages. 2.  Power to know your “environment” •  You can get informa,on about if a message call is possible before do it 3.  Power to change it •  You may create methods, classes, variables on the fly, delete them 2 So, what is method swizzling?
Formally this is method swizzling: –  Replace a selector implementa,on with another implementa,on temporarily or permanently* 3 OK, but for what I can use it?
•  Do you do unit test? •  Have you tried to make a network connec,on from a unit test? •  How did you do it? •  OCMock uses it •  What if I tell you, You can just swizzle any method you want to, from ANY class 4 But wait, there is more!
● 
● 
● 
● 
● 
● 
● 
● 
You can also intercept push no,fica,ons, Sent to background events Sent to foreground Open URLs Handle URLs Proxy request Change persistency storages Possibili,es, possibili,es everywhere 5 An example
Class to Swizzle
Class with replacement
@implementa,on A -­‐(void) foo{ NSLog(@”hi”); } @end @implementa,on A(Swizzled) -­‐(void) bar{ NSLog(@”bye”); } @end 6 An Example (cont.)
Class clazz = [A class]; Method method = class_getInstanceMethod(clazz, @selector(foo)); class_replaceMethod(clazz, @selector(foo), class_getMethodImplementa,on(clazz, @selector(bar)), method_getTypeEncoding(method)); 7 An Example (cont.)
● 
● 
● 
● 
● 
● 
[[[A alloc] init] foo] => bye; [[[A alloc] init] bar] => bye; Selector != Method != IMP Selector, the highest level of abstrac,on Method, metainfo about the selector IMP, the actual code of the selector. 8 Of course, nothing is free
● 
● 
● 
● 
● 
Method swizzling is not atomic. Changes behavior of un-­‐owned code. Possible naming conflicts. Swizzling changes the method's arguments. The order of swizzles maoers. 9 Method swizzling + ARC ugly mix
1.  Remember the sample with class A 2.  OK, what if you want to swizzle the method to add some func,onality besides what foo does? 3.  You not only need to replace, you have to create a new method. 10 Method swizzling + ARC ugly mix (cont.)
What you want to do:
The issues:
@implementa,on A(Swizzled) -­‐(void) bar{ [self __foo]; NSLog(@”bye”); } @end ● 
● 
11 Here, the compiler will complain that __foo is not defined in any interface, well, not yet ;) To cheat the compiler, you need to define a category, just w/the @interface Method swizzling + ARC ugly mix (cont.)
Class clazz = [A class]; Method method = class_getInstanceMethod(clazz, @selector(foo)); class_addMethod(clazz, @selector(__foo), class_getMethodImplementa,on(clazz, @selector(foo)), method_getTypeEncoding(method)); class_replaceMethod(clazz, @selector(foo), class_getMethodImplementa,on(clazz, @selector(bar)), method_getTypeEncoding(method)); 12 Method swizzling + ARC ugly mix (cont.)
● 
● 
● 
[[A alloc] init] foo] => hi bye [[A alloc] init] __foo] => hi [[A alloc] init] bar] => hi bye 13 Not to say the obvious
● 
● 
● 
● 
Difficult to understand (looks recursive) Difficult to debug Scope can be fuzzy. You might be a ghost, but it's scary when people can see you. 14 Conclusions
● 
● 
● 
● 
The Good: you can modify your environment at please, and provide abstrac,on over certain processes. The Bad: side effects, name conflicts, trick the compiler. The Ugly: nasty errors, very hard to debug, because, basically you don't know where the code is. Booom line: with great power comes great responsibility. 15