Swizzle`init`并调用Swift 4中的实际实现

时间:2018-06-14 18:28:22

标签: swift cocoa method-swizzling

我希望调动init(frame:)的{​​{1}},但在里面调用真实的NSView。这可能吗?我知道,我可以通过子类化和覆盖来实现相同的目标,但是在所有地方都需要做太多工作。我不知道如何正确实现swizzled方法来获取递归。我的代码:

init(frame:)

我也尝试过几乎相同但是@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!) } } } 并且得到了递归。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

撇开这是一个非常危险和不明智的混战,如果用于探索和调试之外的任何事情,method_exchangeImplementations的重点是交换实现。这意味着旧的实现变成了混合方法。因此,要调用您自称的旧实现:

@objc func swizzledFrameInit(frame: NSRect) {
    self.swizzledFrameInit(frame: frame)
    self.wantsLayer = true
}

通常,实现您在此处执行的操作的正确方法是在顶级视图中设置wantsLayer。此属性适用于所有子视图。

  

创建图层支持的视图会隐式导致该视图下的整个视图层次结构成为图层支持。因此,视图及其所有子视图(包括子视图的子视图)都成为图层支持的