Currently experimenting with method swizzling
in Objective-C and I have a question. I am trying to understand the proper way to method swizzle and after researching online I stumbled upon this NSHipster post:
http://nshipster.com/method-swizzling/
In the post the author has some method swizzling sample code. I am looking for someone to better explain to me what the author is doing.. In particular I am confused on the didAddMethod
logic. Why is the author not just directly swapping/exchanging
method implementations? My only theory on this is maybe there is some off chance that viewWillAppear:
is not added to UIViewController's method
dispatch_table
yet. Particularly if maybe the category is loaded into memory first before UIViewController
... Is this the reason why? It seems rather odd? Just looking for some more insight/clarity, thanks :)
Your confusion is understandable as this logic is not explained clearly.
First ignore the fact that the example is a category on the specific class
UIViewController
and just consider the logic as though the category was on some arbitrary class, let's call that classTargetClass
.We'll call the existing method we wish to replace
existingMethod
.The category, being on
TargetClass
, adds the swizzling method, which we'll callswizzlingMethod
, toTargetClass
.Important: Note that the function to get an method,
class_getInstanceMethod
, will find the method in the supplied class or any of its superclasses. However the functionsclass_addMethod
andclass_replaceMethod
only add/replace methods in the supplied class.Now there are two cases to consider:
TargetClass
itself directly contains an implementation ofexistingMethod
. This is the easy case, all that needs to be done is exchange the implementations ofexistingMethod
andswizzlingMethod
, which can be done withmethod_exchangeImplementations
. In the article the call toclass_addMethod
will fail, as there is already andexistingMethod
directly inTargetClass
and the logic results in a call tomethod_exchangeImplementations
.TargetClass
does not directly contain an implementation ofexistingMethod
, rather that method is provided through inheritance from one of the ancestor classes ofTargetClass
. This is the trickier case. If you simply exchange the implementations ofexistingMethod
andswizzlingMethod
then you would be effecting (instances of) the ancestor class (and in a way which could cause a crash - why is left as an exercise). By callingclass_addMethod
the article's code makes sure there is anexistingMethod
inTargetClass
- the implementation of which is the original implementation ofswizzlingMethod
. The logic then replaces the implementation ofswizzlingMethod
with the implementation of the ancestor'sexistingMethod
(which has no effect on the ancestor).Still here? I hope that makes sense and hasn't simply sent you cross-eyed!
Another exercise if you're terminally curious: Now you might ask what happens if the ancestor's
existingMethod
implementation contains a call tosuper
... if the implementation is now also attached toswizzlingMethod
inTargetClass
where will that call tosuper
end up? Will it be to implementation in ancestor, which would see the same method implementation executed twice, or to the ancestor's ancestor, as originally intended?HTH
load
is called when aclass
is added in obj-c runtime.https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/#//apple_ref/occ/clm/NSObject/load
So let's say if a
UIViewController
gets added in obj-c runtime which already containsviewWillAppear:
but you want it to be replaced by another implementation. So first you add a new methodxxxWillAppear:
. Now oncexxxWillAppear:
has been added inViewController
class, only then you can replace it.But the author also said :
so he is trying to demonstrate a case where an app might have many view controllers but you do not want to keep replacing for each
ViewController
theviewWillAppear:
implementation. Once the point ofviewWillAppear:
has been replaced, then instead of adding, only the exchange will need to be done.Perhaps source code of Objective C runtime might help :
You can dig more if you want:
http://www.opensource.apple.com/source/objc4/objc4-437/