Bhargav Bhargav - 7 months ago 14
Swift Question

Not able to pass self (which implements a protocol) to init method of a class instantiation.(Swift)

I have a protocol like so

public protocol FooProtocol {
associatedType someType

func doFoo(fooObject:someType) -> Void
}


I have a class that implements this protocol

public class Foo<T> : FooProtocol {
private let _doFoo : (T) -> Void

init<P : FooProtocol where P.someType == T>(_dep : P) {
_doFoo = _dep.doFoo
}

public func doFoo(fooObject: T) {
_doFoo(fooObject)
}
}


Everything upto here looks good to me, Now in another class I implement the FooProtocol with
someType = MyType
, then when I try to initialize the
Foo
class with
T = MyType
by passing
self
in the init method of the
Foo
class I get a compilation error, what am I doing wrong here?

Error message:


" Cannot invoke init with an argument list of type
(_dep: NSObject -> () -> MyView)
"


public class MyView : UIViewController, FooProtocol {

func doFoo(fooObject : MyType) {
...
}

// Here I want to initialize the Foo<T> class
let fooInstant : Foo<MyType> = Foo.init(_dep : self)
// I get the error message on the above line the error
// message reads "Cannot invoke init with an argument list
// of type `(_dep: NSObject -> () -> MyView)`
}


Isn't self conforming to FooProtocol with
someType == MyType
, and since I am trying to init a
Foo
object with
T == MyType
this should technically work yes?

Answer

This actually doesn't appear to be anything to do with your generics or protocol conformance. It's simply that you're trying to pass self before self has been initialised (to be clear, this means that self refers to the class itself in that context – not an instance of the class).

The solution is to use a lazy property like so:

lazy var fooInstant : Foo<MyType> = {
    return Foo.init(_dep : self)
}()

This will now be created when it's first accessed, ensuring that self has been initialised.