Typhoon - How to inject parameter which conforms to PROTOCOL instead of CLASS

654 views Asked by At

I have class which represents logged user

public class User: NSObject {        
    init(authenticator: Authenticator) {        
        self.authenticator = authenticator
    }
    ... 
}

Its only initial arguments is object which conforms to Authenticator protocol

protocol Authenticator
{
    func authenticate(login:String , password:String , handler: (result:AuthenticationResult)->()  )
}

In my case the Auth object is instance of class BackendService

My typhoon assembly definition is:

public dynamic func user() -> AnyObject {
    return TyphoonDefinition.withClass(User.self) {
        (definition) in

        definition.useInitializer("initWithAuthenticator") {
            (initializer) in

            initializer.injectParameterWith( self.backendService() )
        }            
    }
}

Application cause runtime-error

'Method 'initWithAuthenticator' has 0 parameters, but 1 was injected. Do you mean 'initWithAuthenticator:'?'

If i change init method to 'initWithAuthenticator:' it crashes with

'Method 'initWithAuthenticator:' not found on 'PersonalMessages.User'. Did you include the required ':' characters to signify arguments?'
1

There are 1 answers

0
Jasper Blues On

At the present time, it is necessary to add the '@objc' directive to Swift protocols to have them be available for dependency injection with Typhoon. Without it the objective-c runtime's introspection and dynamic dispatch features arent available and these are required.

Similarly, in the case of a class it must extend from NSObject or have the '@objc' directive, otherwise it will also use C++ style vtable dispatch and have (essentially) no reflection. In the case of private vars or methods, they must also have the 'dynamic' modifier.

While vtable dispatch is faster, it prevents runtime method interception which many of Cocoa's most powerful features, such as KVO rely on. So both paradigms are important and its impressive that Swift can switch between them. In the case of protocols though, using the '@objc' directive is a little unfortunate as it implies a 'legacy' behavior. Perhaps 'dynamic' would've been better?

dynamic protocol Authenticator //Not supported but would've been a nicer than '@objc'?

Or perhaps another way to imply that dynamic behavior is required would be to have the protocol extend the NSObject protocol, however this does not work. So using '@objc' is the only choice.

Meanwhile, for classes the requirement to extend NSObject isn't really noticible as far as working with Cocoa/Touch apps goes.