Rus*_*kov 5 objective-c-runtime swift
我正在运行时创建UIView的子类,并layoutSubviews为它提供我的方法实现.我需要做的一件重要事情就是表演super.layoutSubviews().在Objective-C中,我可以使用以下objc_msgSendSuper函数:
Class objectClass = object_getClass(object);
Class superclass = class_getSuperclass(objectClass);
struct objc_super superInfo;
superInfo.receiver = object;
superInfo.super_class = superclass;
typedef void *(*ObjCMsgSendSuperReturnVoid)(struct objc_super *, SEL);
ObjCMsgSendSuperReturnVoid sendMsgReturnVoid = (ObjCMsgSendSuperReturnVoid)objc_msgSendSuper;
sendMsgReturnVoid(&superInfo, @selector(layoutSubviews));
Run Code Online (Sandbox Code Playgroud)
但objc_msgSendSuper方法在Swift中不可用.我应该用什么来做同样的事情?
正如 Martin 所说,objc_msgSendSuper它在 Swift 中不可用,因为它是一个 C 可变参数函数,而 Swift 由于缺乏类型安全性而不会导入该函数。
一种替代方法是使用class_getMethodImplementation来获取指向函数的指针,以调用给定类类型的选择器。从那里,您可以将其转换为 Swift 可以使用 调用的函数类型unsafeBitCast,注意参数和返回类型匹配。
例如:
\n\nimport Foundation\n\nclass C {\n @objc func foo() {\n print("C\'s foo")\n }\n}\n\nclass D : C {\n override func foo() {\n print("D\'s foo")\n }\n}\n\nlet d = D()\n\nlet superclass: AnyClass = class_getSuperclass(type(of: d))!\nlet selector = #selector(C.foo)\n\n// The function to call for a message send of "foo" to a `C` object.\nlet impl = class_getMethodImplementation(superclass, selector)!\n\n// @convention(c) tells Swift this is a bare function pointer (with no context object)\n// All Obj-C method functions have the receiver and message as their first two parameters\n// Therefore this denotes a method of type `() -> Void`, which matches up with `foo`\ntypealias ObjCVoidVoidFn = @convention(c) (AnyObject, Selector) -> Void\n\nlet fn = unsafeBitCast(impl, to: ObjCVoidVoidFn.self)\nfn(d, selector) // C\'s foo\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,像objc_msgSendSuper这样假设桥接到 Obj-C 的返回类型与指针布局兼容。在大多数情况下(包括您的情况)都是如此,但对于返回诸如 之类的类型的方法则不然CGRect,该类型在 Obj-C 中使用 C 结构类型表示。
对于这些情况,您需要改用class_getMethodImplementation_stret:
import Foundation\n\nclass C {\n @objc func bar() -> CGRect {\n return CGRect(x: 2, y: 3, width: 4, height: 5)\n }\n}\n\nclass D : C {\n override func bar() -> CGRect {\n return .zero\n }\n}\n\nlet d = D()\n\nlet superclass: AnyClass = class_getSuperclass(type(of: d))!\nlet selector = #selector(C.bar)\nlet impl = class_getMethodImplementation_stret(superclass, selector)!\n\ntypealias ObjCVoidVoidFn = @convention(c) (AnyObject, Selector) -> CGRect\n\nlet fn = unsafeBitCast(impl, to: ObjCVoidVoidFn.self)\nlet rect = fn(d, selector)\nprint(rect) // (2.0, 3.0, 4.0, 5.0)Run Code Online (Sandbox Code Playgroud)\n\nclass_getMethodImplementation和之间的区别class_getMethodImplementation_stret是由于调用约定的不同 \xe2\x80\x93 字大小的类型可以通过寄存器传回,但是更大尺寸的结构需要间接传回。这很重要class_getMethodImplementation,因为在对象不响应选择器的情况下,它可以传回用于消息转发的 thunk。
另一种选择是使用method_getImplementation,它不执行消息转发,因此不需要区分 stret 和非 stret。
例如:
\n\nlet impl = method_getImplementation(class_getInstanceMethod(superclass, selector)!)\nRun Code Online (Sandbox Code Playgroud)\n\n但请记住,文档指出:
\n\n\n\n\n
class_getMethodImplementation可能比 更快method_getImplementation(class_getInstanceMethod(cls, name))。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |