在Objective-C中调整方法的正确方法

时间:2015-12-28 23:18:43

标签: objective-c objective-c-runtime swizzling method-swizzling

目前在Objective-C中尝试使用方法swizzling,我有一个问题。我试图理解方法混合的正确方法,在网上研究后我偶然发现了这个NSHipster帖子: http://nshipster.com/method-swizzling/

在帖子中,作者有一些方法调整样本代码。我正在寻找一个能够更好地向我解释作者正在做什么的人。特别是我对didAddMethod逻辑感到困惑。为什么作者不仅仅是直接swapping/exchanging方法实现?我唯一的理论是,viewWillAppear: UIViewController's method尚未添加dispatch_table。特别是如果类别在UIViewController之前首先被加载到内存中......这是为什么?看起来很奇怪?只是寻找更多洞察力/清晰度,谢谢:))

2 个答案:

答案 0 :(得分:6)

  

特别是我对didAddMethod逻辑感到困惑。为什么作者不只是直接交换/交换方法实现?

你的困惑是可以理解的,因为这个逻辑没有得到清楚的解释。

首先忽略一个事实,即该示例是特定类UIViewController上的一个类别,并且只考虑逻辑,好像该类别在某个任意类上,让我们调用该类TargetClass

我们会调用我们希望替换existingMethod的现有方法。

TargetClass上的类别将我们称之为swizzlingMethod的混合方法添加到TargetClass

重要:请注意,获取方法class_getInstanceMethod的函数将在提供的类或其任何超类中找到该方法。但是,函数class_addMethodclass_replaceMethod仅在提供的类中添加/替换方法。

现在有两种情况需要考虑:

  1. TargetClass本身直接包含existingMethod的实现。这是一个简单的案例,所有需要做的就是交换existingMethodswizzlingMethod的实现,这可以通过method_exchangeImplementations完成。在文章中,对class_addMethod的调用将失败,因为已经existingMethod 直接在 TargetClass中,逻辑会导致调用method_exchangeImplementations }。

  2. TargetClass 直接包含existingMethod的实现,而是通过从TargetClass的祖先类之一继承来提供该方法。这是一个棘手的案例。如果您只是简单地交换existingMethodswizzlingMethod的实现,那么您将影响祖先类的(实例)(并且可能导致崩溃 - 为什么留下作为练习)。通过调用class_addMethod文章的代码可确保existingMethod中有TargetClass - 其实施是swizzlingMethod的原始实现。然后,逻辑将swizzlingMethod的实现替换为祖先existingMethod的实现(对祖先没有影响)。

  3. 还在吗?我希望这是有道理的,并没有简单地发送你的眼睛!

    如果你最后好奇的另一个练习:现在你可能会问,如果祖先的existingMethod实现包含对super的调用,会发生什么......如果现在实现的话还附加到swizzlingMethod TargetClass superpio-stop-all号召唤到哪里?它是在祖先中执行,它会看到相同的方法实现执行两次,还是原始的祖先的祖先?

    HTH

答案 1 :(得分:0)

在obj-c运行时添加M(1,3,0.9时会调用

load

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/#//apple_ref/occ/clm/NSObject/load

因此,假设在obj-c运行时中添加了class,它已经包含UIViewController,但您希望它被另一个实现替换。首先,您添加一个新方法viewWillAppear:。 现在,xxxWillAppear:课程中添加xxxWillAppear:后,您才可以替换它。

但作者也说:

  

例如,假设我们想要跟踪每个视图控制器在iOS应用中向用户呈现的次数

所以他试图演示一个应用可能有很多视图控制器但你不想继续替换每个ViewController ViewController实现的情况。一旦viewWillAppear:的点被替换,则不需要添加,只需要进行交换。

也许Objective C运行时的源代码可能会有所帮助:

viewWillAppear:

如果你愿意,你可以挖掘更多:

http://www.opensource.apple.com/source/objc4/objc4-437/