Swizzle `init` 并在内部调用实际实现,Swift 4
Swizzle `init` and invoke actual implementation inside, Swift 4
我想调配 NSView
的 init(frame:)
但在里面调用真正的 init(frame:)
。这可能吗?我知道,我可以通过子类化和重写来实现相同的目标,但是要在所有地方更改它会做太多工作。我不知道如何正确实现 swizzled 方法来避免递归。我的代码:
@objc func swizzledFrameInit(frame: NSRect) {
//?? how to call init here
self.wantsLayer = true
}
static func swizzleInitDescription() {
DispatchQueue.once(token: "swizzleInitDescription") {
let originalInitWithFrameSelector = #selector(NSView.init(frame:))
let swizzledFrameSelector = #selector(NSView.swizzledFrameInit(frame:))
let originalFrameInit = class_getInstanceMethod(self, originalInitWithFrameSelector)
let swizzledFrameInit = class_getInstanceMethod(self, swizzledFrameSelector)
let didAddSwizzledFrameInit = class_addMethod(self, originalInitWithFrameSelector, method_getImplementation(swizzledFrameInit!), method_getTypeEncoding(swizzledFrameInit!))
if didAddSwizzledFrameInit {
class_replaceMethod(self, swizzledFrameSelector, method_getImplementation(originalFrameInit!), method_getTypeEncoding(originalFrameInit!))
} else {
method_exchangeImplementations(originalFrameInit!, swizzledFramaInit!)
}
}
}
我也尝试了几乎相同的方法,但使用 convenience init
并得到了递归。任何帮助将不胜感激。
撇开如果用于探索和调试以外的任何事情,这是一个非常危险且不明智的调整,method_exchangeImplementations
的要点是它 交换 实现.这意味着旧的实现变成了 swizzled 方法。所以要调用你自己调用的旧实现:
@objc func swizzledFrameInit(frame: NSRect) {
self.swizzledFrameInit(frame: frame)
self.wantsLayer = true
}
一般来说,实现您在这里所做的事情的正确方法是在顶层视图上设置 wantsLayer
。 属性 适用于所有子视图。
Creating a layer-backed view implicitly causes the entire view hierarchy under that view to become layer-backed. Thus, the view and all of its subviews (including subviews of subviews) become layer-backed
我想调配 NSView
的 init(frame:)
但在里面调用真正的 init(frame:)
。这可能吗?我知道,我可以通过子类化和重写来实现相同的目标,但是要在所有地方更改它会做太多工作。我不知道如何正确实现 swizzled 方法来避免递归。我的代码:
@objc func swizzledFrameInit(frame: NSRect) {
//?? how to call init here
self.wantsLayer = true
}
static func swizzleInitDescription() {
DispatchQueue.once(token: "swizzleInitDescription") {
let originalInitWithFrameSelector = #selector(NSView.init(frame:))
let swizzledFrameSelector = #selector(NSView.swizzledFrameInit(frame:))
let originalFrameInit = class_getInstanceMethod(self, originalInitWithFrameSelector)
let swizzledFrameInit = class_getInstanceMethod(self, swizzledFrameSelector)
let didAddSwizzledFrameInit = class_addMethod(self, originalInitWithFrameSelector, method_getImplementation(swizzledFrameInit!), method_getTypeEncoding(swizzledFrameInit!))
if didAddSwizzledFrameInit {
class_replaceMethod(self, swizzledFrameSelector, method_getImplementation(originalFrameInit!), method_getTypeEncoding(originalFrameInit!))
} else {
method_exchangeImplementations(originalFrameInit!, swizzledFramaInit!)
}
}
}
我也尝试了几乎相同的方法,但使用 convenience init
并得到了递归。任何帮助将不胜感激。
撇开如果用于探索和调试以外的任何事情,这是一个非常危险且不明智的调整,method_exchangeImplementations
的要点是它 交换 实现.这意味着旧的实现变成了 swizzled 方法。所以要调用你自己调用的旧实现:
@objc func swizzledFrameInit(frame: NSRect) {
self.swizzledFrameInit(frame: frame)
self.wantsLayer = true
}
一般来说,实现您在这里所做的事情的正确方法是在顶层视图上设置 wantsLayer
。 属性 适用于所有子视图。
Creating a layer-backed view implicitly causes the entire view hierarchy under that view to become layer-backed. Thus, the view and all of its subviews (including subviews of subviews) become layer-backed