Objective-C method replacement

Source: Internet
Author: User

Objective-C method replacement

(Method replacement for fun and profit)

This article will discuss method replacement and swizzling in objective-C ).

 

Overriding Methods)

Overriding methods is common in any object-oriented language and is mainly used in subclasses. Re-write a method in the subclass, and then you can use this override method in the subclass instance.

 

For a class that you cannot control its instantiation, sometimes you may want to re-write a method of it, although a bit crazy. Subclass is not possible, because you have no chance to subclass your subclass.

 

Camouflage)

Posing is a very interesting technology, but it is outdated because it is no longer supported in 64-bit and objective-C runtime in the iPhone environment. through this camouflage, You Can subclass and disguise this subclass as its parent class. Like magic, runtime applies this sub-class to various places. At this time, method rewriting is useful. Since it has been abandoned, you don't have to pay too much for it.

 

 

Categories)

The category technology can be used to conveniently repeat an existing class:

@ Implementationnsview (myoverride)

-(Void) drawrect:
(Nsrect) r

{

// This will replace the commonly used-[nsview drawrect:]

[[Nscolor bluecolor] set];

Nsrectfill (R );

}

@ End

 

This method is only applicable to the functions implemented in the parent class of the target class. If you directly rewrite the methods in the target class, using the category will bring two problems:

  1. It cannot call the previous implementation of the method. After replacement, the previous implementation is completely rewritten. However, in most cases, you only want to add some functions and do not expect them to be completely replaced.
  2. If multiple category replicas exist, the runtime does not guarantee which one will actually be used.
Swizzling !)

The use of a technology called swizzling can solve the above two problems for classification, which can call the old implementation and avoid the uncertainty caused by multiple category. Its secret is to use a different function name to rewrite, and then exchange them by runtime.

 

First, rewrite with a different name:

@ Implementationnsview (myoverride)

-(Void) override_drawrect:
(Nsrect) r

{

// Call the old implementation. Because they have been replaced

[Self override_drawrect: R];

[[Nscolor bluecolor] set];

Nsrectfill (R );

}

@ End

 

I don't know if you are the same as me. The first time I saw the code, I thought it was a recursive call .) In fact, this new method has been called against the original function during execution (but it has not been done yet. Let's look down !). During running, call override_drawrect: The method actually calls the old implementation.

 

Next, you need to write some code to complete the exchange:

Voidmethodswizzle (Class C, Sel origsel, Sel
Overridesel)

{

Method origmethod = class_getinstancemethod (C, origsel );

Method overridemethod = class_getinstancemethod (C, overridesel );

There are two situations to consider. The first case is that the overridden method is not implemented in the target class (notimplemented), but is implemented in the parent class. The second case is that this method already exists in the target class (does existin the class itself ). The two cases should be treated differently.

 

Note: The purpose of this function is to replace the original method with an overwrite method. However, the override method may be rewritten in the parent class or in the subclass .)

 

In the first case, you should first Add a new implementation method (override) in the target class, and then replace the method of rewriting with the original implementation (original one ).

 

The runtime function class_addmethod returns a failure if it finds that the method already exists. It can also be used for check:


If (class_addmethod (C, origsel, method_getimplementation (overridemethod), method_gettypeencoding (overridemethod )))

{

 

If the method is successfully added (the method that is rewritten in the parent class), replace the method in the target class with the old implementation:

Class_replacemethod (C, overridesel, method_getimplementation (origmethod), method_gettypeencoding (origmethod ));

}

 

(: Addmethod will point the method of the target class to a new implementation. Use replacemethod to point the new method to the original implementation, so that the switching operation is completed .)

 

If the addition fails, it is the second case (the method of rewriting in the target class ). In this case, the exchange can be completed through method_exchangeimplementations:

Else

{

Method_exchangeimplementations (origmethod, overridemethod );

}

}

 

In the second case, because class_getinstancemethod will return the implementation of the parent class. If it is directly replaced, the implementation of the parent class will be replaced, rather than the implementation in the target class. (The detailed function description is here)

 

For example, replace-[nsview description]. If nsview does not implement-description (optional), you can obtain the nsobject method. If you call method_exchangeimplementations,
You will replace the nsobject method with your code. This should not be what you want, right?

 

Finally, you can call it at a proper location. For example, in a + load method:

+ (Void) Load

{

Methodswizzle (self, @ selector (drawrect :), @ selector (override_drawrect :));

}

 

Direct override)

The previous content is indeed difficult to understand. The concept of swizzling is indeed somewhat odd, especially in the transfer of functions, which may seem somewhat distorted. The following describes a more concise, understandable, and implemented method.

 

In this way, you no longer need to save the old method or dynamically distinguish [self override_drawrect: R]. We will implement it from scratch.

 

Compared with storing the original method in a new method, a global pointer is used for saving:

Void (* gorigdrawrect) (ID, Sel,
Nsrect );

 

Then assign values in + LOAD:

+ (Void) Load

{

Method origmethod = class_getinstancemethod (self, @ selector (drawrect :));

Gorigdrawrect = (void *) method_getimplementation (origmethod );

(I like to convert it to void *, because it is much more input than those long and strange function pointers .)

 

Then replace it with the new implementation as described earlier. Because class_replacemethod itself will attempt to call class_addmethod and method_setimplementation, you can directly call class_replacemethod.

 

The implementation is as follows:

Method origmethod = class_getinstancemethod (self,
@ Selector (drawrect :));
Gorigdrawrect = (void *) class_replacemethod (self, @ selector (drawrect :), (IMP) overridedrawrect, method_gettypeencoding (origmethod ))

 

Finally, the method for implementing the rewrite is as follows. The difference is that here is a method, not a method:

Staticvoidoverridedrawrect (nsview * Self, Sel
_ Cmd, nsrect R)

{

Gorigdrawrect (self, _ cmd, R );

[[Nscolor bluecolor] set];

Nsrectfill (R );

}

Of course, this method is not so elegant, but I think it is easier to use.

 

The obligatory warning)

Rewriting is not your own class and is dangerous! Avoid doing this as much as possible, or you will be able to handle it as carefully as possible.

Original article address: fridayqa, 2010-01-29, method replacement for fun and profit

Reference: Objective-cruntime reference

Reprinted please indicate the source:

Http://blog.csdn.net/horkychen

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.