Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.2k views
in Technique[技术] by (71.8m points)

swift - Using delegates on generic protocol

I have got this code:

protocol GenericProtocol: class {
    associatedtype type
    func funca(component: type)
}

class MyType<T> {

    weak var delegate: GenericProtocol? // First error

    var t: T

    init(t: T) {
        self.t = t
    }

    func finished() {
        delegate?.funca(component: t) // Second error
    }

}

class UsingGenericProtocol: GenericProtocol {

    let myType: MyType<Int>
    typealias type = Int

    init() {
        myType = MyType<Int>(t: 0)
    }

    func funca(component: Int) {

    }

}

I want to use delegates with a given type. The code will not compile because I got this errors:

Protocol 'GenericProtocol' can only be used as a generic constraint because it has Self or associated type requirements

And:

Member 'funca' cannot be used on value of protocol type 'GenericProtocol'; use a generic constraint instead

I can omit this error by removing the type from the protocol, make it Any and then casting it to the right type, but I thought generics should cover this problem. Is there any way I can get this code to compile? Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The difference between generics and associated types is that generics are specified at instantiation, associated types during implementation. So you cannot use the protocol type as a concrete type because the associated type depends on the implementing type.

However, there are a few workarounds:

1) Use the type of the delegate as a generic type:

class MyType<Delegate: GenericProtocol> {
    typealias T = Delegate.type
    ...
}

2) Use a common protocol on your delegate method instead of an associated type:

protocol CommonProtocol { ... }

protocol DelegateProtocol {
    func funca(component: CommonProtocol)
}

3) Use closures for type erasure (this is also done in the Swift Standard Library for the Sequence protocol with AnySequence<Element>)

struct AnyGenericProtocol<GenericType>: GenericProtocol {
    typealias type = GenericType
    private let f: (GenericType) -> ()

    init<G: GenericProtocol>(_ g: GenericProtocol) where G.type == GenericType {
        f = { component in
            g.funca(component: component)
        }
    }

    func funca(component: GenericType) {
        f(component)
    }
}

class MyType<T> {
    var delegate: AnyGenericProtocol<T>
    ...
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...