2016-04-08 59 views
0

我想在swift类(someClass)上应用反射来调用带有一个参数(someArg)的init方法,我设法获得了init选择器和具有1个参数的IMP,但是当我调用IMP,它最终调用没有参数的init。在下面的Playground中,我总是会打印出“调用错误的init”。 如果我删除重写的init我得到以下错误:Swift中的参数化初始化器反射

fatal error: use of unimplemented initializer 'init()' for class '__lldb_expr_15.someClass' 

我缺少什么?

import UIKit 

public class someClass:NSObject{ 
    init(num:someArg){ 
     print("called the right init") 
    } 

    override init(){ 
     print("called the wrong init") 
    } 
} 

public class someArg:NSObject{ 
    override init(){ 

    } 
} 


public class Test{ 

    func reflect(){ 

     let classType: NSObject.Type = someClass.self as NSObject.Type 
     let (initializerWithOneArgImp,selector) = getInitializerWithArguments(classType, argumentsCount: 1) 

     typealias initializerWithOneArgImpType = @convention(c) (AnyObject, Selector, AnyObject) -> (AnyObject) 

     let callback = unsafeBitCast(initializerWithOneArgImp , initializerWithOneArgImpType.self) 
     callback(classType,selector,someArg()) 
    } 

    func getInitializerWithArguments(classType:AnyClass, argumentsCount:Int)->(IMP,Selector){ 

     var methodCount:CUnsignedInt = 0 
     let methodList = class_copyMethodList(classType.self, &methodCount) 
     let n : Int = Int(methodCount) 

     for var i: Int = 0; i < n; i++ { 

      let methodSelector = method_getName(methodList[i]) 
      let methodName:String = String(_sel:methodSelector) 

      if(methodName == "init") 
      { 
       let methodArgumentsCount = method_getNumberOfArguments(methodList[i]) 

       if(methodArgumentsCount == UInt32(argumentsCount) + 1) 
       { 
        return (method_getImplementation(methodList[i]),methodSelector) 

       } 
      } 
     } 
     return (nil,nil) 
    } 
} 
var test = Test() 
test.reflect() 

回答

0

事实证明,非参数化的init有两个参数在默认情况下,和参数初始化将有“initWithNum”作为方法名。

if(methodName.hasPrefix("init")) 
{ 
    let methodArgumentsCount = method_getNumberOfArguments(methodList[i]) 

    if(methodArgumentsCount == UInt32(argumentsCount) + 2) 
    { 
      return (method_getImplementation(methodList[i]),methodSelector) 

     } 
}