【问题标题】:Swizzle `init` and invoke actual implementation inside, Swift 4Swizzle `init` 并调用内部的实际实现,Swift 4
【发布时间】:2023-04-09 11:11:01
【问题描述】:

我想调配init(frame:)NSView,但在里面调用真正的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 并得到了递归。任何帮助将不胜感激。

【问题讨论】:

    标签: swift cocoa method-swizzling


    【解决方案1】:

    撇开这是一个非常危险和不明智的混搭,如果用于探索和调试以外的任何事情,method_exchangeImplementations 的重点在于它交换 实现。这意味着旧的实现变成了混合的方法。所以要调用你自己的旧实现:

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

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

    创建一个支持层的视图会隐式地导致该视图下的整个视图层次成为支持层。因此,视图和它的所有子视图(包括子视图的子视图)变成了 layer-backed

    【讨论】:

      最近更新 更多