我试图用Swift中的文件URL来捕获InputStream的初始化。我已经在NSInputStream类的Objective中成功地实现了这种捕获。问题是在交换初始化符之后,不触发swizzled方法。此外,在方法交换之后,直接调用swizzled方法并不会导致它的执行,这意味着它的实现已经成功地交换了。我想知道,这种奇怪行为的原因是什么,因为方法是成功的,但还不清楚,哪种方法被混乱的方法所取代。在Swift中提供了InputStream swizzling当前实现的示例。
private let swizzling: (AnyClass, Selector, Selector) -> () = { forClass, originalSelector, swizzledSelector in
if let originalMethod = class_getInstanceMethod(forClass, originalSelector),
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
extension InputStream {
@objc dynamic func swizzledInit(url: URL) -> InputStream? {
print("Swizzled constructor")
return self.swizzledInit(url: url)
}
static func Swizzle() {
swizzling(InputStream.self, #selector(InputStream.init(url:)), #selector(swizzledInit(url:)))
}
}发布于 2022-01-19 21:29:56
NSInputStream是由NSStream的具体子类组成的类集群的抽象超类,这些子类提供对流数据的标准只读访问。
这里的关键是:当您创建一个InputStream时,返回的对象将不是InputStream类型,而是InputStream的一个(私有)子类。与基础集合类型(NSArray/NSMutableArray、NSDictionary/NSMutableDictionary等)非常相似的是,与之接口的父类型并不是要处理的有效类型:当您将这些类型中的一种表示为+alloc时,返回的对象通常是私有子类。
在大多数情况下,这是不相关的实现细节,但在您的示例中,由于您试图对初始化器进行切换,您实际上关心的是从+alloc返回的值,因为您是在对从未被调用的初始化器进行处理。
在InputStream的特定情况下,从+[NSInputStream alloc]返回的值属于私有NSCFInputStream类,这是与CoreFoundation共享的有效的免费桥接类型。这是在任何时候都可以更改的私有实现细节,但是您可以对该类上的初始化器进行切换:
guard let class = NSClassFromString("NSCFInputStream") else {
// Handle the fact that the class is absent / has changed.
return
}
swizzling(class, #selector(InputStream.init(url:)), #selector(swizzledInit(url:)))请注意,如果您为app提交了一个应用程序,那么包含私有类名可能会影响评审过程。
https://stackoverflow.com/questions/70772148
复制相似问题