Swift 5.5使用Method Swizzling替换NSURL的initWithString崩溃如何解决
问题原因
1. 直接崩溃原因
你的代码崩溃在let originalMethod = class_getInstanceMethod(NSURL.self, original)!这一行,原因是class_getInstanceMethod返回了nil,你强制解包可选值触发了致命错误。
出现nil的原因是NSURL属于类簇,initWithString:的具体实现没有放在公开的NSURL基类中,而是存在于苹果内部私有的子类实现里,直接从NSURL类上无法获取到这个实例方法的指针。
2. 其他隐藏问题
就算你解决了方法获取的问题,代码还有以下问题会导致功能异常:
- 方法签名不匹配:你定义的
log_initWithString没有声明返回值,Swift默认推断为Void,但原生initWithString:的返回值是可选NSURL实例,方法类型编码不匹配,交换后会出现内存错误。 - 覆盖场景缺失:Swift中的URL是结构体类型,它的
init(string:)构造器有原生Swift实现,大部分场景下不会桥接调用ObjC的NSURL方法,就算hook成功NSURL的对应方法,也覆盖不到Swift中URL的创建场景。 - 动态派发缺失:你给NSURL扩展加的
log_initWithString只加了@objc,缺少dynamic修饰符,无法保证走ObjC runtime的动态派发,可能导致runtime无法识别到这个方法。
优化建议
类簇的Swizzling风险极高,苹果的内部实现随时可能调整导致逻辑失效甚至崩溃,如果只是需要拦截URL创建逻辑,更稳妥的方案是自己封装一层统一的URL创建工具方法。
如果一定要用Swizzling实现,可以尝试hookNSURL的+URLWithString:类方法,这个方法的实现直接存在于NSURL类上,更容易获取,同时注意匹配方法签名,确保返回值类型正确。
内容的提问来源于stack exchange,提问作者Faustino
相关产品推荐
相关产品推荐

