有没有办法监视一个特殊对象的方法调用并得到通知?我希望在调用 [object someMethod] 时调用函数“Observer”。我知道我可以使用 objective c KVO 监视对象的值变化,但它没有告诉我调用堆栈(哪些函数)导致对象的值发生变化。是否有类似 KVO 的东西,但对于方法,我可以在哪里监视函数调用?如果现有框架无法实现,关于如何实现此类功能的任何建议?谢谢!
最佳答案
我假设您不控制要拦截其方法的类的实现,因此按照@Conrad Shultz 的建议更改 API 是不可行的。我想到了其他几种方法。
首先是方法调配。其工作方式是使用类别将具有相同签名的方法添加到类中,然后交换要拦截的方法的实现和添加的方法。您添加的方法将在调用“自身”之前和/或之后调用您想要的任何 Hook 。由于您交换了实现,调用“自身”实际上调用了原始方法。那里有很多关于 method swizzling 的很好的解释。 Here's one.
另一种选择可能是将对象包装在 NSProxy 中并使用 -forwardInvocation
传递调用。同样,有很多资源详细解释了代理和调用转发,所以我不会在这里重复。 Here's one.这种方法的局限性在于您必须具有必要的访问权限才能在您的代理中交换真实对象。如果对象是在某些 API 中私下创建的,则此方法将无用。
另一种方法是做 KVO 所做的事情。 Key-Value Observing 的工作原理是在运行时创建一个类的子类,然后执行所谓的 isa
- swizzling 将现有实例的类更改为新的动态子类。没有理由不能为要拦截其实例方法的类创建一个运行时生成的子类,然后让运行时生成的子类对该方法的实现调用父类(super class)之前和/或之后的任何其他 Hook (真正的)方法的实现。这有可能让您更轻松地拦截不止一个方法,但是不会有一种直接的方法来拦截具有任意签名的任意方法,因为您必须想出一种方法来调用您的钩子(Hook)而不破坏堆栈,然后向量关闭进入主要实现。以这种方式拦截具有任意签名的任意方法可能涉及在汇编中编写蹦床,然后尾部调用真正的实现,就像 objc_msgSend 所做的那样。这是一个 good article on runtime subclassing .
从历史的角度来看:过去也有一个名为 poseAsClass 的功能也允许这样做,但它已被删除,我认为自 SnowLeopard-ish 时间框架以来,所以它可能是一个非启动器。
这些选项中的任何一个都会对性能产生影响,并且都非常“聪明”。我这么说并不是为了拍拍自己的背——我没有想出任何这些,只是反省它们。但多年来我注意到,当一个解决方案感觉过于“聪明”时,这是一个明显的迹象,表明我正在走向最终的灾难。换句话说,如果您正在使用的 API 没有为您提供拦截这些方法调用的方法,则可能表明您应该从不同的角度来解决问题。但显然,您的里程可能会有所不同。
关于objective-c - Objective C - 在调用方法时得到通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9247801/