Swift swizzling 初始化函数
Swift swizzling init function
我正在尝试使用 Swift 中的文件 URL 捕获 InputStream 的初始化。我已经在 Objective-C 中为 NSInputStream class 成功实现了这样的捕获。
问题是在交换初始化器之后,不会触发 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:)))
}
}
NSInputStream
is an abstract superclass of a class cluster consisting of concrete subclasses of NSStream
that provide standard read-only access to stream data.
这里的关键:当你创建一个InputStream
时,你得到的对象将不是InputStream
类型,而是[=11]的(私有)子class =].与 Foundation 集合类型(NSArray
/NSMutableArray
、NSDictionary
/NSMutableDictionary
等非常相似),您与之交互的父类型不是 有效的 您正在处理的类型:当您 +alloc
这些类型之一时,返回的对象通常是私有子 class.
在大多数情况下,这是不相关的实现细节,但在您的情况下,因为您正在尝试调整 初始化程序 ,您实际上关心从 +alloc
,因为你正在调配一个永远不会被调用的初始化程序。
在InputStream
的具体情况下,从+[NSInputStream alloc]
返回的值是私有的NSCFInputStream
class,这是共享的有效免费桥接类型与 CoreFoundation。 这是私有实现细节,可能随时更改,但您可以在 that 上调整初始化程序class 改为:
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 Store 审核,包含私人 class 名称可能会影响审核流程。
我正在尝试使用 Swift 中的文件 URL 捕获 InputStream 的初始化。我已经在 Objective-C 中为 NSInputStream class 成功实现了这样的捕获。 问题是在交换初始化器之后,不会触发 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:)))
}
}
NSInputStream
is an abstract superclass of a class cluster consisting of concrete subclasses ofNSStream
that provide standard read-only access to stream data.
这里的关键:当你创建一个InputStream
时,你得到的对象将不是InputStream
类型,而是[=11]的(私有)子class =].与 Foundation 集合类型(NSArray
/NSMutableArray
、NSDictionary
/NSMutableDictionary
等非常相似),您与之交互的父类型不是 有效的 您正在处理的类型:当您 +alloc
这些类型之一时,返回的对象通常是私有子 class.
在大多数情况下,这是不相关的实现细节,但在您的情况下,因为您正在尝试调整 初始化程序 ,您实际上关心从 +alloc
,因为你正在调配一个永远不会被调用的初始化程序。
在InputStream
的具体情况下,从+[NSInputStream alloc]
返回的值是私有的NSCFInputStream
class,这是共享的有效免费桥接类型与 CoreFoundation。 这是私有实现细节,可能随时更改,但您可以在 that 上调整初始化程序class 改为:
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 Store 审核,包含私人 class 名称可能会影响审核流程。