I."Black Magic": Method Swizzling uses the runtime feature to replace the implementation of one approach with the implementation of another, or to use the four-dimensional understanding of runtime-to modify dispatch Table let the imp of a method correspond to our designated IMP.
two. Example Description : For example, we want to record the number of occurrences of each viewcontroller in an app.
three. Example Analysis :
- The first idea is that in the viewcontroller of the moment (viewdidappear) I use the recording tool to record a log.
1 @implementationMyviewcontroller ()2 3- (void) Viewdidappear: (BOOL) Animated4 {5 [Super viewdidappear:animated];6 7 //Custom Code8 9 //LoggingTen [Logging logwitheventname:@ "My view did appear"]; One } A - -- (void) Mybuttonclicked: (ID) Sender the { - //Custom Code - - //Logging + [Logging logwitheventname:@ "my button clicked"]; -}
Methods of violence* The disadvantage is that I want to record all the VC then I will be in all the VC to write the code? That clever you will think of catagory. But think about it. You need to inherit Uiviewcontroller, Uitableviewcontroller, Uicollectionviewcontroller all of these VC add categories, And it violates the purpose of Apple's design catagory (to add some code to the class instead of replacing it)
- The second way of thinking is our protagonist method swizzling today.
three.Demo:
1 #import<objc/runtime.h>2 3 @implementationUiviewcontroller (Tracking)4 5+ (void) Load {6 //guaranteed to be replaced only once7 Staticdispatch_once_t Oncetoken;8Dispatch_once (&oncetoken, ^{9Classclass= [Selfclass];TenSEL Originalselector =@selector (viewwillappear:); OneSEL Swizzledselector =@selector (xxx_viewwillappear:); A -Method Originalmethod = Class_getinstancemethod (class, originalselector); -Method Swizzledmethod = Class_getinstancemethod (class, swizzledselector); the -BOOL Didaddmethod = -Class_addmethod (class, - Originalselector, + method_getimplementation (swizzledmethod), - method_gettypeencoding (Swizzledmethod)); + A if(didaddmethod) { atClass_replacemethod (class, - Swizzledselector, - method_getimplementation (originalmethod), - method_gettypeencoding (Originalmethod)); -}Else { - method_exchangeimplementations (Originalmethod, swizzledmethod); in } - }); to } + - #pragmaMark-method swizzling the *- (void) Xxx_viewwillappear: (BOOL) Animated { $ //Here we need to explain, because we need to call the implementation of the parent class in Viewwillappear. This line of code is called when the Xxx_viewwillappear and Viewwillappear methods have been replaced. So it's not a seemingly recursive form.Panax Notoginseng [self xxx_viewwillappear:animated]; - the[Logging Logwitheventname:nsstringfromclass ([selfclass])]; + } A the @end
Add categories to Uiviewcontroller
Explanation 1. The only thing that may need to be explained here is class_addMethod
. The first attempt to add the original selector is to do a layer of protection, because if the class is not implemented originalSelector
, but its parent class implements it, it class_getInstanceMethod
returns the method of the parent class. This method_exchangeImplementations
replaces the method of the parent class, which is certainly not what you want. So we first try to add orginalSelector
, if already exist, and then use the method_exchangeImplementations
original method to implement the implementation of the new method to swap out
Explanation 2:swizzling always executes in +load, Because method swizzling affects global state, it's important to minimize the possibility of RAC E conditions. +load is guaranteed to being loaded during class initialization, which provides a modicum of consistency for changing system- Wide behavior. By contrast, +initialize provides no such guarantee of the when it'll be executed-in fact, it may never is called, if that C Lass is never messaged directly by the App.da probably means that because the square +load is guaranteed to be in the class initialization load, thus changing the system behavior provides a bit of consistency. By contrast, there is no guarantee of +init (), and if the app is not called directly, it may never be executed.
1 void(goriginalviewdidappear) (ID, SEL, BOOL);2 3 voidNewviewdidappear (Uiviewcontroller *Self , SEL _cmd, BOOL animated)4 {5 //Call Original Implementation6 goriginalviewdidappear (self, _cmd, animated);7 8 //Logging9[Logging Logwitheventname:nsstringfromclass ([selfclass])];Ten } One A+ (void) Load - { -Method Originalmethod =Class_getinstancemethod (Self, @selector (viewdidappear:)); theGoriginalviewdidappear = (void*) method_getimplementation (Originalmethod); - - if(!Class_addmethod (Self, @selector (viewdidappear:), (IMP) newviewdidappear, method_gettypeencoding (Originalmethod ))) { - method_setimplementation (Originalmethod, (IMP) newviewdidappear); + } -}
Instead of replacing the old method directly
Four. Summary : What is the dangers of Method swizzling in Objective C?
- Method swizzling is not atomic
- Changes behavior of un-owned code
- Possible Naming conflicts
- Swizzling changes the method ' s arguments
- The Order of Swizzles matters
- Difficult to understand (looks recursive)
- Difficult to debug
iOS Development Stuff (iv) The dark arts of the OBJECTIVE-C runtime