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));
但是Swift中没有objc_msgSendSuper方法.我应该用什么来做同样的事情?
一种替代方法是使用class_getMethodImplementation
以获取指向函数的指针,以调用给定类类型的选择器.从那里,你可以将它转换为Swift可以使用unsafeBitCast调用的函数类型,注意参数和返回类型匹配.
例如:
import Foundation class C { @objc func foo() { print("C's foo") } } class D : C { override func foo() { print("D's foo") } } let d = D() let superclass: AnyClass = class_getSuperclass(type(of: d))! let selector = #selector(C.foo) // The function to call for a message send of "foo" to a `C` object. let impl = class_getmethodImplementation(superclass,selector)! // @convention(c) tells Swift this is a bare function pointer (with no context object) // All Obj-C method functions have the receiver and message as their first two parameters // Therefore this denotes a method of type `() -> Void`,which matches up with `foo` typealias ObjCVoidVoidFn = @convention(c) (AnyObject,Selector) -> Void let fn = unsafeBitCast(impl,to: ObjCVoidVoidFn.self) fn(d,selector) // C's foo
请注意,与objc_msgSendSuper类似,这假设桥接到Obj-C的返回类型是与指针兼容的布局.在大多数情况下(包括你的)都是如此,但对于返回类型的方法(例如CGRect,使用C结构类型在Obj-C中表示)则不然.
对于这些情况,您需要使用class_getmethodImplementation_stret:
import Foundation class C { @objc func bar() -> CGRect { return CGRect(x: 2,y: 3,width: 4,height: 5) } } class D : C { override func bar() -> CGRect { return .zero } } let d = D() let superclass: AnyClass = class_getSuperclass(type(of: d))! let selector = #selector(C.bar) let impl = class_getmethodImplementation_stret(superclass,selector)! typealias ObjCVoidVoidFn = @convention(c) (AnyObject,Selector) -> CGRect let fn = unsafeBitCast(impl,to: ObjCVoidVoidFn.self) let rect = fn(d,selector) print(rect) // (2.0,3.0,4.0,5.0)
class_getmethodImplementation和class_getmethodImplementation_stret之间的区别是由于调用约定的不同 – 字大小的类型可以通过寄存器传回,但是更大的结构需要间接传回.这对于class_getmethodImplementation很重要,因为它可以在对象没有响应选择器的情况下传回thunk以进行消息转发.
另一种选择是使用method_getImplementation,它不执行消息转发,因此不需要区分stret和非stret.
例如:
let impl = method_getImplementation(class_getInstanceMethod(superclass,selector)!)
class_getmethodImplementation
may be faster thanmethod_getImplementation(class_getInstanceMethod(cls,name))
.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。