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

杀马特。学长 韩版系。学妹 提交于 2019-12-23 01:12:09

问题


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?


回答1:


This actually doesn't appear to be anything to do with your generics or protocol conformance. It's simply that you're trying to access self in your property assignment before self has been initialised (default property values are assigned during initialisation).

The solution therefore is to use a lazy property like so:

lazy var fooInstant : Foo<MyType> = Foo(_dep : self)

This will now be created when it's first accessed, and therefore after self has been initialised.




回答2:


It is very much important to understand the context of self in the place where it is used. In that context, self doesn't mean an instance of MyView.

You can, however get it to work by doing this:

let fooInstant : Foo<String> = Foo.init(_dep : MyView())

I cannot say more without understanding what you want to do here.




回答3:


So seems like this works

public class MyView : UIViewController, FooProtocol {

    var fooInstant : Foo<MyType>!

    public func initializeFooInstant(){
        fooInstant  = Foo.init(_dep : self)
    }


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

I think system does not let you access self to initialise let properties because there is no guarantee that self is fully initialised when your let property is being initialised.

In the above case you will just have to make sure that fooInstance is initialised before accessing it else the program will crash.

Hope this helps.



来源:https://stackoverflow.com/questions/36996573/not-able-to-pass-self-which-implements-a-protocol-to-init-method-of-a-class-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!