vendredi 8 avril 2016

Parameterized Initializer Reflection in Swift

I am trying to apply reflection on a swift class (someClass) to invoke an init method that takes one argument (someArg), I managed to get the init selector and IMP that has 1 argument, but when I invoke the IMP it ends up calling the init with no arguments. In the Playground below I always get "called the wrong init" printed. What am I missing?

     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.memory)

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

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





Aucun commentaire:

Enregistrer un commentaire