swift - Swizzle `init` 并调用内部的实际实现,Swift 4
问题描述
我想调酒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
并得到了递归。任何帮助,将不胜感激。
解决方案
撇开这是一个非常危险且不明智的混合,如果用于除探索和调试之外的任何事情,重点method_exchangeImplementations
是它交换实现。这意味着旧的实现变成了混合的方法。因此,要调用您自己的旧实现:
@objc func swizzledFrameInit(frame: NSRect) {
self.swizzledFrameInit(frame: frame)
self.wantsLayer = true
}
通常,实现您在此处执行的操作的正确方法是wantsLayer
在顶级视图上进行设置。此属性适用于所有子视图。
创建一个支持层的视图会隐式地导致该视图下的整个视图层次结构成为支持层的。因此,视图和它的所有子视图(包括子视图的子视图)变成了 layer-backed
推荐阅读
- javascript - Phaser3 - 无法旋转汽车并且瓷砖地图不完全可见
- html - 如何使用 html 和 css 在右箭头符号内创建文本设计
- http - Flutter/Dart DNS 解析超时
- npm - 按 CTRL+C 时的 npm 错误代码 ELIFECYCLE
- c++ - MacOS 上的 CTest 错误:找不到测试可执行文件
- c# - .NETFramework 4.6.2 客户端到 .NET Core 3.1 服务器 GRPC 客户端调用失败
- php - 禁用警告,在本地主机响应通知
- jasmine - 如何使用茉莉花测试翻译服务中的字段标签
- java - JAVA SDK 中的 Google BigQuery 代理设置
- c# - c#如何在游戏中将我的图片坐标转换为网格坐标