younata / Ra

Dependency Injector for swift
MIT License
8 stars 2 forks source link

Class-level configuring of initializers #5

Closed younata closed 8 years ago

younata commented 9 years ago

This is likely only possible for objects that inherit from NSObject.

Basically, it would be nice to have a protocol that can be optionally implemented to specify how to create the object. For example:

class MyClass : Injectable {
    class func raInitializer(injector: Ra.Injector) -> (Void) -> (Any) {
        return {
            let myObj = MyClass(injector.create("a"), b: injector.create("b"))
            return myObj
        }
    }
}

This way, we can attempt to reduce some of the configuration for items that require special setup and what not.

We might also use this to introduce an injector property to anything that implements the protocol.

If we can use this to enable creating arbitrary object w/o registering them first, then that would be amazing. If not, then it's still awesome.

younata commented 9 years ago

What's interesting is that you can totally declare a protocol with a static/class method, E.G.

public protocol Injectable {
    static func create(injector: Injector) -> Injectable
}

But, if you try to use it, you get an Accessing members of protocol type value Injectable.Type is unimplemented, E.G.

if let blah = klass as? Injectable.Type {
    return blah.create(self) // Error: Accessing members of protocol type value Injectable.Type is unimplemented
}

Which basically tells me that this isn't yet possible to call class methods/functions on protocols in swift.

There's somewhat of a workaround that I can do, the compiler will totally accept

public protocol Injectable {
    func configure(injector: Injector)
    init()
}

Which can then be initialized using:

if let blah = klass as? Injectable.Type {
    let obj = blah()
    obj.configure(self)
    return obj
}

Which is... less desirable than just "create/configure with injector in one fell swoop", because it encourages us to not use 'let' variables (which need to be set before either the initializer ends, or super.init() is called), which is one of the best features about swift. However, I don't want perfect to be the enemy of good here.

@tjarratt Thoughts?