The C language is a static language, which works through function calls, so that we have determined how the program runs during compilation. Objective-C is a dynamic language. It does not call class methods to execute functions, but sends messages to objects. After an object receives a message, it finds a matching method to run it. In this way, the C language compilation is moved to the runtime for additional flexibility.
There is a @ selector in Objective-C, which is translated into "selector" in many places ". In fact, for instance objects of the class, the class method is represented by a number, not a long string with this character. With this @ selector, you can convert the name of this method into the corresponding number. After a class is determined, the @ selector value of each method is actually fixed. Here, you can think of method swizzling as something, if we have A method A, @ selector (A) is A number. After receiving A message, our object searches for the corresponding method and runs it. -- if, we replace the number @ selector (B) with the number of the original @ selector (A). At this time, although the object receives A message, it will run the B method!
In iOS, this can be fully implemented. When do we need to do this? I think there are two times:
1. Cracking. Needless to say, this is definitely a powerful tool for cracking.
2. During the development and debugging process, if you are not sure about the method in a library or feel that you need to expand it, you can write one for yourself to replace it. Because Objective-C has Category, the extension function is not necessary, but it is convenient to add some print statements during debugging.
For example, the lowercaseString method in NSString. If I don't know what this method is doing, I can write a method to replace it. In this method, a print statement is added, in this way, the log is clear at a glance.
First, add an NSString Category.
@interface NSString (wzTest)- (NSString*)myLowerString;@end@implementation NSString (wzTest)- (NSString*)myLowerString{ NSString *lowerString = [self myLowerString]; NSLog(@"%@ => %@", self, lowerString); return lowerString;}@end
Here is an explanation. In the myLowerString method, it seems that it calls itself recursively. However, we will use the original lowercaseString method to replace the self-written myLowerString method. Therefore, we did not call ourselves here, but called the original lowercaseString method. Pay attention to this.
Next, replace the system's original lowercaseString method and use the method in runtime.
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString)); Method swapMethod = class_getInstanceMethod([NSString class], @selector(myLowerString)); method_exchangeImplementations(originalMethod, swapMethod); NSString *testStr = @"thIs is THE Test STRING"; NSLog(@"lowerString of testStr=%@", [testStr lowercaseString]);
Let's take a look at the log results:
22:17:55. 514 testTableView [1582: a0b] thIs is THE Test STRING => this is the test string
22:17:55. 514 testTableView [1582: a0b] lowerString of testStr = this is the test string
We can see that the lowercaseString method is used in the system, but the actual execution is our new method. When you do not need to do this, you can disable the method swizzling method to restore it.
In our example, a print statement is added, and more operations can be performed. This is a very useful method for debugging with a third-party library. You can easily view the variable content or do some other work. After debugging, disable method swizzling to work properly.