2016-04-08 66 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) 

     } 
}