Understanding Objective-c Runtime (iv) Method swizzling

Source: Internet
Author: User

After the Objective-c object receives the message, what method is called to be resolved during runtime. Then you might ask: Does the method corresponding to the given selection sub-name change at runtime? Yes, that's it. Using this feature can be a huge advantage because we do not need the source code or the ability to override the class itself by inheriting subclasses. As a result, the new functionality will take effect in all instances of this class, not just those subclass instances that overwrite the related methods. This scheme is the famous "method swizzling", which is often referred to as "method leveling" or "method blending" or "method mixing".

Method swizzling

The method list of the class maps the name of the selector to the relevant method implementation, enabling the dynamic Message-dispatch system to find a way to reconcile it accordingly. These methods are represented in the form of function pointers, which are called IMP (IMP is explained in understanding Objective-c Runtime (a) preparatory knowledge).

For a chestnut, NSString class can respond to LowerCaseString, uppercasestring, capitalizedstring and other selectors. Each selector in this mapping table (selector table, also often referred to as the "selector sheet") is mapped to a different imp, as shown in:

For a chestnut, NSString class can respond to LowerCaseString, uppercasestring, capitalizedstring and other selectors. Each selector in this mapping table (selector table, also often referred to as the "selector sheet") is mapped to a different imp, as shown in:

Several methods provided by the OBJECTIVE-C runtime system can be used to manipulate this table. Developers can add selector to it, change the method implementation of one of the selector, and exchange pointers that are mapped by two selector. After several operations, the method of the class becomes as follows:

In the new mapping table, more than one selector named Newselector, the implementation of lowercasestring and uppercasestring are interchangeable. None of the above modifications need to write subclasses, as long as the layout of the method table is modified, it is reflected on all NSString instances in the program.

implementation of Exchange two methods

Now, using the sample code to deduce the "swap NSString LowerCaseString and uppercasestring method implementation", the implementation is as follows:

-(void) viewdidload {[Super viewdidload];        NSString *astring = @ "ABCDEFG";    LowerCaseString and uppercasestring before: NSLog (@ "lowercasestring and uppercasestring before Exchange:");    NSLog (@ "Lowercase of the string:%@", [astring lowercasestring]);        NSLog (@ "Uppercase of the string:%@", [astring uppercasestring]); The Class_getinstancemethod method is obtained by means of the methods type method Originalmethod = Class_getinstancemethod ([NSString class], @selector (    lowercasestring));        Method Swappedmethod = Class_getinstancemethod ([NSString class], @selector (uppercasestring));        Method_exchangeimplementations Exchange Map Pointer method_exchangeimplementations (Originalmethod, Swappedmethod);    LowerCaseString and Uppercasestring after Exchange: NSLog (@ "lowercasestring and uppercasestring after Exchange:");    NSLog (@ "Lowercase of the string:%@", [astring lowercasestring]); NSLog (@ "Uppercase of the string:%@", [astring uppercasestring]);} /* Output: lowercasestring and uppercasestring before swap: lowercase of the string:abcdefguppercase ofThe string:abcdefglowercasestring and uppercasestring after Exchange: lowercase of the string:abcdefguppercase of the string:abcdefg* /

This shows how to exchange the implementation of two methods, but in practical applications, such as the direct exchange of two methods to achieve, its significance is not very good, unless the egg pain. However, this approach can be used to add new functionality to the existing method implementations.

Modify the behavior of an existing method

The best way to introduce a skill is to ask for specific requirements and then use it to compare with other solutions.

So, let's take a look at our needs: tracking and analyzing the user behavior of the App. Simply put, that is, when the user sees a view or clicks on a button, the event is written down.

Manually add

@implementation Myviewcontroller ()-(void) Viewdidappear: (BOOL) animated{    [Super viewdidappear:animated];    Custom code     //Logging    [Logging logwitheventname:@ "My view did appear"];} -(void) mybuttonclicked: (ID) sender{    //Custom code     //Logging    [Logging logwitheventname:@ "my button Clicked "];}

The downside of this approach is also obvious: it destroys the cleanliness of the code. Because the Logging code itself does not belong to the main logic in Viewcontroller. As your project expands and your code grows, your viewcontroller will be littered with Logging code. At this point, it becomes difficult to find the code for an event record, and it is easy to forget the code that added the event record.

You might want to add the code for the event record in the overridden method with inheritance or category. The code can be long like this:

-(void) Myviewdidappear: (BOOL) animated{    [Super viewdidappear:animated];    Custom code     //Logging    [Logging logwitheventname:nsstringfromclass ([self class]);} -(void) mybuttonclicked: (ID) sender{    //Custom code     //Logging    nsstring *name = [NSString stringWithFormat: @ "My button in%@ are clicked", Nsstringfromclass ([self class]);    [Logging logwitheventname:name];}

The code for Logging is similar, and it is possible to remove it from the primary logic by inheriting or categorization the associated method. But it also brings new problems:

    1. You need to inherit Uiviewcontroller,uitableviewcontroller,uicollectionviewcontroller all these viewcontroller, or add categories to them;
    2. The ButtonClick method in each Viewcontroller cannot be named the same;
    3. You can't control how others instantiate your subclass;
    4. For categories, you have no way to invoke the original method implementation, most of the time, we rewrite a method just to add some code, rather than completely replace it;
    5. If there are two categories that implement the same method, the runtime cannot guarantee which class of methods will be called.

Method Swizzling's practice

Method Swizzling is to add a method to the body of the method that is called in the body log_viewDidAppear: viewDidAppear: ; log_viewDidAppear: viewDidAppear: Well, some around, look at the picture:

log_viewDidAppear:the implementation code for the new method can be written like this:

-(void) Log_viewdidappear: (BOOL) animated{    [self log_viewdidappear:animated];    Logging    [Logging logwitheventname:nsstringfromclass ([self class]);}

It seems that this code will fall into a recursive loop, but keep in mind that this method is prepared and viewDidAppear: method-interchangeable. So, in runtime, the log_viewDidAppear: selection of the sub-corresponding is the original viewDidAppear: method of implementation; Similarly, when sending an viewdidappear: Message to an object, as the above code will be called, and the first sentence of this code is that [self log_viewDidAppear:animated]; this is actually called the original viewDidAppear: Implementation code of the method ...

After the log_viewDidAppear: implementation is defined, it has to viewDidAppear: be exchanged with:

The Class_getinstancemethod method is obtained by means of the methods type method Originalmethod = Class_getinstancemethod ([NSString class], @selector ( Viewdidappear:)); Method Swappedmethod = Class_getinstancemethod ([NSString class], @selector (log_viewdidappear:));//Method_ Exchangeimplementations Exchange Map Pointer method_exchangeimplementations (Originalmethod, Swappedmethod);

How do I schedule method swizzling-related code?

In general, runtime-related code will be organized in category, so log_viewDidAppear: the implementation of the above method will be written in a uiviewcontroller category, for example UIViewController(log) . The code associated with the Exchange method is written in the category load. Because the Load method is executed before runtime, the Load method is called as long as the header file where the category resides is referenced, and the same class allows multiple load methods between different category These load methods will be called (the only problem is who first who is behind).

With the method swizzling scheme, developers can add logging to the black box method of "completely unaware of the implementation" (completely opaque, "completely opaque"), which is very helpful for program debugging, however, this practice is only useful when debugging programs. Few people use the above "Method-leveling technology" to permanently change the functionality of a class outside of the debug program, because if used carelessly, it can cause too much damage and is difficult to debug. It must not be used just because the Objective-c language has this feature. If misused, it makes the code difficult to read and maintainable.

In short, method swizzling only a controversial technology, there are a lot of analysis of the article, the bottom of the resources have links.

AOP (Aspect oriented programming)

I learned a new concept when reading the blog, "Method swizzling and AOP practice." AOP Simply put, in the Objective-c world, AOP is the use of the runtime feature to add custom code to the specified method, and method Swizzling is one of the ways to implement AOP.

References
    1. "Effective OBJECTIVE-C 2.0";
    2. "iOS Development Advanced";
    3. "Method swizzling and AOP practice";
    4. Great god Mattt Thompson (afnetworking author) "Method swizzling";
    5. "Objective-c hook Scheme (a): Method Swizzling";
    6. What is the dangers of Method swizzling in Objective C?;
    7. "Objective-c Runtime"

Understanding Objective-c Runtime (iv) Method swizzling

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.