IOS之方法混写(swizzling.)
来源:互联网 发布:轮回转世是真的吗 知乎 编辑:程序博客网 时间:2024/06/07 07:40
OC中的混写(swizzling)是指透明地把一个方法换成另外一个。简明的说就是在运行时替换方法。利用方法混写可以改变那些没有源代码的对象(包括系统对象)的行为。
方法混写的代码看起来相对比较直观的,举个例子说明一下,之前做本地化翻译的时候就有用到 swizzling 方法。直接去swizze方法 awakeFromNib 然后替换成自己的方法实现以实现本地化翻译。详细可以看这篇文章:IOS本地化应用程序。
主要用到的代码也就这两句:
+(void)load { // Autoload : swizzle -awakeFromNib with -localizeNibObject as soon as the app (and thus this class) is loaded Method localizeNibObject = class_getInstanceMethod([NSObject class], @selector(localizeNibObject)); Method awakeFromNib = class_getInstanceMethod([NSObject class], @selector(awakeFromNib)); method_exchangeImplementations(awakeFromNib, localizeNibObject); }
-(void)localizeNibObject { //本地化操作.... // Call the original awakeFromNib method [self localizeNibObject]; // this actually calls the original awakeFromNib (and not localizeNibObject) because we did some method swizzling }
今天又跑回去github上看了一下AGi18n这个开源项目,作者将原来的代码全部都换成了分类实现了,看起来更加的直观,当同样也还是通过 swizzling 实现。
如 NSobject + AGi18n 分类代码:
#import "NSObject+AGi18n.h"#import <objc/runtime.h>@implementation NSObject (AGi18n)//By default do nothing when localizing- (void)localizeFromNib {}#pragma mark - Method swizzling+ (void)load { Method awakeFromNibOriginal = class_getInstanceMethod(self, @selector(awakeFromNib)); Method awakeFromNibCustom = class_getInstanceMethod(self, @selector(awakeFromNibCustom)); //Swizzle methods method_exchangeImplementations(awakeFromNibOriginal, awakeFromNibCustom);}- (void)awakeFromNibCustom { //Call standard methods [self awakeFromNibCustom]; //Localize [self localizeFromNib];}@end
上面代码 交换了 awakeFromNib 和 awakeFromNibCustom 方法的实现,在程序一启动的时候就去执行。由于该类是 NSObject 的分类,而所有控件都是继承 NSObject 的,这样,本地化操作只需在需要本地化的控件分类里重写一下 localizeFromNib 这个方法即可,以UIButton为例,本地化操作就变得非常简单了。
#import "UIButton+AGi18n.h"@implementation UIButton (AGi18n)- (void)localizeFromNib { //Replace text with localizable version NSArray *states = @[@(UIControlStateNormal), @(UIControlStateHighlighted), @(UIControlStateDisabled), @(UIControlStateSelected), @(UIControlStateApplication)]; for (NSNumber *state in states) { NSString *title = [self titleForState:state.integerValue]; if (title.length > 0) { [self setTitle:[[NSBundle mainBundle] localizedStringForKey:title value:@"" table:nil] forState:state.integerValue]; } }}@end
-----------------------------------------------------------------------------------------------------分割线-----------------------------------------------------------------------------------------------------------------------------
《IOS 7 Programming:Pushing the Limits》一书中对方法混写举了一个在NSNotificationCenter中添加观察者时打印日志的例子。通过上下两个例子的对比,AGi18n在 swizzling 时还是欠缺部分考虑的。
@interface NSObject(RNSwizzle)+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP;@end@implementation NSObject(RNSwizzle)+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP{ Class class = [self class]; Method origMethod = class_getInstanceMethod(class, origSelector); IMP origIMP = method_getImplementation(origMethod); if (!class_addMethod(self, origSelector, newIMP, method_getTypeEncoding(origMethod))) { method_setImplementation(origMethod, newIMP); } return origIMP;}@end接下来看看细节。首先给这个方法传递一个选择器和一个函数指针(IMP)。我们要做的是把该方法的当前实现替换为新实现,并返回旧实现的指针以便以后调用。需要考虑3种情况:类可能直接实现了这个方法,方法可能是类层次结构中的某个父类实现的,或者方法根本没有实现。如果该类或某个父类实现了这个方法,调用 class_getInstanceMethod 会返回一个 IMP,否则就返回 NULL。
如果方法根本没有实现,或者是某个父类实现的,那就需要用 class_addMethod 添加方法,这跟通常的覆盖方法是一样的。如果 class_addMethod 失败了,我们就知道了是此类直接实现了正在混写的方法,那么就转而用 method_setImplementation 来把旧实现替换为 新实现。
好了之后,返回原来的 IMP,调用者怎么用返回值是它自己的事。
参考:《IOS 7 Programming:Pushing the Limits》
1 0
- IOS之方法混写(swizzling.)
- iOS之运行时机制及方法混写method swizzling
- iOS之方法变换(Method Swizzling)
- iOS runtime学习之Method Swizzling(方法调配技术)
- iOS - Runtime 之 Method Swizzling(方法交换)
- iOS Method Swizzling方法替换
- IOS Method swizzling(方法调配)
- IOS 开发之 Method Swizzling
- IOS 中方法重组(Method swizzling)
- iOS开发 Method Swizzling 方法替换
- iOS 备忘录Hook Method Method Swizzling方法
- iOS 面试题 之method swizzling
- iOS黑魔法之Method Swizzling
- iOS开发之深入了解Objective-C Runtime、Method Swizzling、Method Swizzling 和 AOP 实践
- IOS Method Swizzling 替换方法 Objective-C的hook方案
- iOS Runtime应用实例(二)method swizzling(方法交叉)
- iOS开发 Method Swizzling 可以调换两个方法
- ios Method Swizzling
- python 速度优化
- 依赖项属性的组成
- 安卓基础总结 intent activity 页面间传递信息
- 《从0到1》读书笔记第3章“所有成功的企业都是不同的”第1记:成功企业垄断,失败企业竞争
- 黑马程序员——7k面试题—银行业务调度问题
- IOS之方法混写(swizzling.)
- 进制与编码
- .net源码摘录,已展开
- 九度OJ-1138-大数的求余
- 实现一个通讯录(数组实现)
- 安卓基础总结 Service相关
- 在RegisterCommon()函数
- leetcode Sort List
- IOS 隐藏键盘