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)); 但是Swift中没有objc_msgSendSuper方法.我应该用什么来做同样的事情?
As Martin says,objc_msgSendSuper在Swift中不可用,因为它是一个C variadic函数,由于缺乏类型安全性,Swift不会导入它.
一种替代方法是使用 例如: 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)!) 但请记住the documentation notes:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |