Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

what is_the_best_way_of_method_swizzling

1 695 vues

Publié le

what is_the_best_way_of_method_swizzling

Publié dans : Technologie
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

what is_the_best_way_of_method_swizzling

  1. 1. What is the best way of method swizzling? Akira Miki Repro Inc. iOS meetup@voyage Feb 14, 2015
  2. 2. Who am I?
  3. 3. Akira Miki CTO / Repro @ae06710
  4. 4. Reproduce real user behavior
  5. 5. Reproduce User behavior
  6. 6. Quantitative Analytics
  7. 7. Crash Report (with UIView Breadcrumbs and Movie)
  8. 8. What’s method swizzling?
  9. 9. Replacing the implementation of that method with another > Meta Programming
  10. 10. Like that: #import <Foundation/Foundation.h> #import <objc/runtime.h> @interface GeneralSwz : NSObject @end @implementation GeneralSwz + (void)load { Method originalMethod = class_getInstanceMethod(self, @selector(foo)); Method swizzledMethod = class_getInstanceMethod(self, @selector(swz_foo)); method_exchangeImplementations(originalMethod, swizzledMethod); } - (void)foo { NSLog(@"original foo method"); } - (void)swz_foo { NSLog(@"swizzed foo method"); [self swz_foo]; } @end
  11. 11. Calling `foo method` Flow: Call `foo` IMP `swz_foo` Method `foo` execute `swz_foo ` struct  objc_method            SEL  method_name                  OBJC2_UNAVAILABLE;            char  *method_types            OBJC2_UNAVAILABLE;            IMP  method_imp                    OBJC2_UNAVAILABLE;   } Dispatch table Developer iOS
  12. 12. > method_exchangeImplementations(original, swizzled); It’s very easy.
 But, this has a few problems.
  13. 13. Replace timing • Cannot check user define callback method and replace this. • Another third-party library replacement same method at the same time on another thread @implementation GeneralSwz + (void)load { Method originalMethod = class_getInstanceMethod(self, @selector(foo)); Method swizzledMethod = class_getInstanceMethod(self, @selector(swz_foo)); method_exchangeImplementations(originalMethod, swizzledMethod); } @end
  14. 14. Target scope • Not by super class • 
 
 
 
 @interface Bare : NSObject @end @implementation Bare - (void)foo { NSLog(@"Bare foo method"); } @end @interface InheritedSwz : Bare @end @implementation InheritedSwz + (void)load { Method originalMethod = class_getInstanceMethod(self, @selector(foo)); Method swizzledMethod = class_getInstanceMethod(self, @selector(swz_foo)); method_exchangeImplementations(originalMethod, swizzledMethod); } // we got `-[Bare swz_foo]: unrecognized selector` - (void)swz_foo { NSLog(@"Inherited swz_foo method"); [self swz_foo]; } @end
  15. 15. Conflict • Naming conflict can happen @implementation CategorySwz // swizzling foo method to swz_foo - (void)foo { NSLog(@"original foo method"); } - (void)swz_foo { NSLog(@"swizzed foo method"); [self swz_foo]; } @end @implementation CategorySwz (category) - (void)swz_foo { // Call this only NSLog(@"Cateogry swz_foo method"); } @end
  16. 16. Assertion • if check about assertion for keep everything running smoothly, don’t work @implementation AssertSwz // Swizzle method foo to swz_foo - (void)foo { assert([NSStringFromSelector(_cmd) isEqualToString:@"foo"]); NSLog(@"original foo method"); } - (void)swz_foo { NSLog(@"swizzed foo method"); [self swz_foo]; } @end
  17. 17. Best swizzling behavior is… • Swizzle on demand timing • Thread safe • Effect to super class • Can’t override replacement method • _cmd return original method name
  18. 18. Prepare @interface Bare : NSObject @end @implementation Bare - (void)foo { NSLog(@"original foo method"); } @end @interface General : Bare @end @implementation General @end Base Class - (void)foo General Class Inherited Class - (void)foo Swizzle `foo` method
  19. 19. Solution-1 • Prepare new implementation as function
 • 
 
 • And replace with `method_setImplementation` void _replacement_Method(id self, SEL _cmd) { NSLog(@"swizzed foo method”); ((void(*)(id,SEL))__original_Method_Imp)(self, _cmd); } static IMP __original_Method_Imp; @implementation InheritedBare + (void)swizzle { Method m = class_getInstanceMethod( [self class], @selector(foo)); __original_Method_Imp = method_setImplementation( m, (IMP)_replacement_Method ); } @end
  20. 20. Solution-2 • Lock thread and call once
 • 
 
 #import <libkern/OSAtomic.h> 
 + (void)swizzle { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ OSSpinLock lock = OS_SPINLOCK_INIT; OSSpinLockLock(&lock); Method m = class_getInstanceMethod( [self class], @selector(foo)); __original_Method_Imp = method_setImplementation( m, (IMP)_replacement_Method ); OSSpinLockUnlock(&lock); }); }
  21. 21. #import <objc/runtime.h> #import <libkern/OSAtomic.h> static IMP __original_Method_Imp;
 void _replacement_Method(id self, SEL _cmd) { // it will pass assert([NSStringFromSelector(_cmd) isEqualToString:@"foo"]); NSLog(@"swizzed foo method"); ((void(*)(id,SEL))__original_Method_Imp)(self, _cmd); } @implementation GoodSwz + (void)swizzle { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ OSSpinLock lock = OS_SPINLOCK_INIT; OSSpinLockLock(&lock); Method m = class_getInstanceMethod( [self class], @selector(foo)); __original_Method_Imp = method_setImplementation( m, (IMP)_replacement_Method ); OSSpinLockUnlock(&lock); }); } @end
  22. 22. And class method swizzling is… • as hard as what we just saw
  23. 23. So, you want to implement all these yourself? 
 No, use “rabovik/RSSwizzle”!
  24. 24. > These bad practices aren’t really a big deal if you’re writing standalone applications - http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/
  25. 25. Sample Code and references • https://github.com/ae06710/swizzle-sample • Method Swizzling - Written by Mattt Thompson on February 17th, 2014 • http://nshipster.com/method-swizzling/ • The Right Way to Swizzle in Objective-C • http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/ • What are the Dangers of Method Swizzling in Objective C? • http://stackoverflow.com/questions/5339276/what-are-the-dangers-of-method-swizzling-in- objective-c/8636521#8636521 • rabovik/RSSwizzle • https://github.com/rabovik/RSSwizzle • http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/libkern/OSAtomic.h • Objective-C Runtime Reference • https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/ index.html#//apple_ref/c/func/method_getImplementation
  26. 26. [Experts wanted] || ( && )
  27. 27. Thank you :)

×