2015-12-16 26 views
0

我跟随Swift & the Objective-C Runtime,它适用于普通方法。如何在swift中调试init

我喜欢swizzle init方法,从我的理解来看,init就像一个类方法。所以我尝试使用swizzling init作为实例和类方法。但它似乎没有工作

我可以使它工作使用Objective C,只是不知道如何使它在斯威夫特工作

从我gist

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); 
      } 
     } 
+0

什么是你的类继承?我认为swizzling只能用于从NSObject继承的类或者使用'@ objc'定义为目标c类。 –

+0

@CleverError我链接到我的要点在这个问题上,你可以看看 – onmyway133

回答

3

摘录当创建一个选择方法,您应该将其基于Obj C方法签名,因为使用Obj C运行时完成混合。

所以原来的选择应该是

initWithIdentifier:source:destination:

现在这变得有点古怪,因为您的init方法被定义,使得需要在第一个参数标签(由具有identifier两次),该要使用选择实际上是

ftg_initWithIdentifier:source:destination:

唯一documentation我可以找到关于它的讨论从作业的翻译j 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()) 
} 
+0

我试过了,但它似乎并没有工作 – onmyway133

+0

我更新了我的答案,我忘了添加更改。对于init, –

0

您也可以调配类扩展。这里的交叉混合的一个例子的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() 
    } 
} 
+0

不起作用 –

相关问题