欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > iOS - Method Swizzling

iOS - Method Swizzling

2025/4/22 2:22:02 来源:https://blog.csdn.net/Batac_Lee/article/details/145099179  浏览:    关键词:iOS - Method Swizzling

让我详细总结一下 Method Swizzling 的使用和注意事项:

1. 基本实现

// 基本的 Method Swizzling 实现
@implementation UIViewController (Tracking)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// 1. 获取原始方法和替换方法Method originalMethod = class_getInstanceMethod(self, @selector(viewDidAppear:));Method swizzledMethod = class_getInstanceMethod(self, @selector(track_viewDidAppear:));// 2. 尝试添加方法实现BOOL didAddMethod = class_addMethod(self,@selector(viewDidAppear:),method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));// 3. 如果添加成功,直接替换实现if (didAddMethod) {class_replaceMethod(self,@selector(track_viewDidAppear:),method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));} else {// 4. 添加失败,说明方法已存在,直接交换实现method_exchangeImplementations(originalMethod, swizzledMethod);}});
}// 新方法实现
- (void)track_viewDidAppear:(BOOL)animated {// 1. 调用原始实现[self track_viewDidAppear:animated];  // 注意:这里实际会调用原始的 viewDidAppear:// 2. 添加新的功能[self trackViewPageAppear];
}@end

2. 注意事项

2.1 执行时机

// 1. 在 +load 方法中执行
+ (void)load {// 在这里执行 swizzling// 因为 +load 在类加载时调用,比较安全
}// 2. 避免在 +initialize 中执行
+ (void)initialize {// 不要在这里执行 swizzling// 因为 +initialize 可能被调用多次
}

2.2 线程安全

// 使用 dispatch_once 确保只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{// swizzling 代码
});

2.3 方法命名

// 使用清晰的前缀避免命名冲突
- (void)xyz_swizzledMethod {// 新的实现
}// 避免使用
- (void)swizzledMethod {  // 可能造成命名冲突
}

2.4 子类处理

// 检查当前类是否真正实现了该方法
+ (void)swizzleMethod:(SEL)originalSelector {Class class = [self class];// 确保方法存在于当前类,而不是继承自父类Method originalMethod = class_getInstanceMethod(class, originalSelector);if (method_getImplementation(originalMethod) == method_getImplementation(class_getInstanceMethod([NSObject class], originalSelector))) {return;  // 方法来自基类,不进行 swizzling}// 进行 swizzling
}

2.5 方法签名

// 确保方法签名匹配
- (void)swizzled_method:(id)arg1 withObject:(id)arg2 {// 参数类型和数量必须与原方法完全匹配
}

3. 常见陷阱

3.1 递归调用

// 错误示例
- (void)swizzled_method {[self swizzled_method];  // 死循环!
}// 正确示例
- (void)swizzled_method {// 在 swizzling 后,这里会调用原始实现[self swizzled_method];  // 添加新功能
}

3.2 父类方法

// 避免重复 swizzling
static BOOL isSwizzled = NO;+ (void)load {if (!isSwizzled) {// 执行 swizzlingisSwizzled = YES;}
}

4. 最佳实践

4.1 封装 Swizzling

@implementation NSObject (Swizzling)+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel {Method origMethod = class_getInstanceMethod(self, origSel);Method altMethod = class_getInstanceMethod(self, altSel);if (!origMethod || !altMethod) {return NO;}class_addMethod(self,origSel,class_getMethodImplementation(self, origSel),method_getTypeEncoding(origMethod));class_addMethod(self,altSel,class_getMethodImplementation(self, altSel),method_getTypeEncoding(altMethod));method_exchangeImplementations(class_getInstanceMethod(self, origSel),class_getInstanceMethod(self, altSel));return YES;
}@end

4.2 文档化

// 清晰的文档说明
/*** 替换 viewDidAppear: 方法用于追踪页面显示* 警告:此方法会影响所有 UIViewController 实例* 在 +load 方法中调用,确保在应用启动时完成替换*/
+ (void)swizzleViewDidAppear {// swizzling 实现
}

总结:

  1. 在 +load 中执行
  2. 使用 dispatch_once
  3. 检查方法存在性
  4. 正确处理方法签名
  5. 避免递归调用
  6. 注意子类影响
  7. 清晰的命名约定
  8. 完善的文档说明

Method Swizzling 是一个强大但危险的特性,需要谨慎使用。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词