如何在swift中debugginginit
我跟随Swift和Objective-C运行时 ,它适用于正常的方法。
我喜欢swizzle init方法,从我的理解来看,init就像是一个类方法。 所以我尝试作为实例和类方法swizzling初始化。 但似乎没有工作
我可以使用Objective C工作,只是想知道如何使它在Swift中工作
从我的要点摘录
dispatch_once(&Static.token) { let originalSelector = Selector("init:source:destination:") let swizzledSelector = Selector("ftg_init:source:destination:") let originalMethod = class_getClassMethod(self, originalSelector) let swizzledMethod = class_getClassMethod(self, swizzledSelector) let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) if didAddMethod { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) } else { method_exchangeImplementations(originalMethod, swizzledMethod); } }
在为方法创buildselect器时,应该将其从Obj C方法签名中取出,因为使用Obj C运行时来完成混合。
所以原来的select器应该是
initWithIdentifier:source:destination:
现在这变得有些怪异,因为你的init方法被定义了,所以需要第一个参数的标签(通过identifier
两次),你想要使用的select器实际上是
ftg_initWithIdentifier:source:destination:
我能find的唯一文档是关于从Obj C到Swift的翻译,但是看起来Swift和Obj C正好相反
接下来, init...
是一个实例方法,所以你需要做两个改变。 您需要将class_getClassMethod
更改为class_getInstanceMethod
并且需要从您的ft_init...
方法中删除class
。
所以,当所有的说法和完成,你的代码应该看起来像这样(这对我工作)
dispatch_once(&Static.token) { let originalSelector = Selector("initWithIdentifier:source:destination:") let swizzledSelector = Selector("ftg_initWithIdentifier:source:destination:") let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) if didAddMethod { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } func ftg_init(identifier identifier: String!, source: UIViewController, destination: UIViewController) -> UIStoryboardSegue { return ftg_init(identifier: identifier, source: source, destination: destination.ftg_resolve()) }
您也可以在课程扩展中进行调整。 下面是一个调整UIViewController的viewDidLoad
的例子:
extension UIViewController { // We cannot override load like we could in Objective-C, so override initialize instead public override static func initialize() { // Make a static struct for our dispatch token so only one exists in memory struct Static { static var token: dispatch_once_t = 0 } // Wrap this in a dispatch_once block so it is only run once dispatch_once(&Static.token) { // Get the original selectors and method implementations, and swap them with our new method let originalSelector = #selector(UIViewController.viewDidLoad) let swizzledSelector = #selector(UIViewController.myViewDidLoad) let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) // class_addMethod can fail if used incorrectly or with invalid pointers, so check to make sure we were able to add the method to the lookup table successfully if didAddMethod { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } } // Our new viewDidLoad function // In this example, we are just logging the name of the function, but this can be used to run any custom code func myViewDidLoad() { // This is not recursive since we swapped the Selectors in initialize(). // We cannot call super in an extension. self.myViewDidLoad() print(#function) // logs myViewDidLoad() } }