Oscar Apeland
Oscar Apeland

Reputation: 6662

Specifying a return type for a protocol function in the declaration of a class that conforms to that protocol

I'm using Swift 3, and I'd like to accomplish something I'm not sure is possible. My backend has a couple of different endpoints for different content types which pages the response in different ways etc. I am trying to create a generic protocol that can be implemented for every content type.

protocol DynamicContentFetcher {
    func content() -> MutableObservableArray<Any>
    func getNext()
    func refresh()
}

One of those instances is AdSearch.

class AdSearch: DynamicContentFetcher {
    var results = MutableObservableArray<DynamicAd>([])
    func content() -> MutableObservableArray<Any> {
        return results
    }

That return does not compile with error Cannot convert return expression of type MutableObservableArray<DynamicAd> to return type 'MutableObservableArray<Any>, which makes sense.

What would be nice, was if I could init my classes conforming to DynamicContentFetcher like AdSearch<DynamicAd> and use that value in <> to do func content() -> MutableObservableArray<#Specified Type#> in the protocol. Is this possible with Swift?

MutableObservableArray is a class from the Bond framework, a reactive programming pod.

Upvotes: 3

Views: 674

Answers (1)

dfrib
dfrib

Reputation: 73176

You can use an associatedtype in your protocol, and use this as the typeholder in the return type of content() in you protocol:

struct MutableObservableArray<T> {}

protocol DynamicContentFetcher {
    associatedtype T
    func content() -> MutableObservableArray<T>
    //func getNext()
    //func refresh()
}

struct DynamicAd {}

class AdSearch: DynamicContentFetcher {
    var results = MutableObservableArray<DynamicAd>()
    func content() -> MutableObservableArray<DynamicAd> {
        return results
    }
}

What would be nice, was if I could init my classes conforming to DynamicContentFetcher like AdSearch<DynamicAd> and use that value in <> to do func content() -> MutableObservableArray<#Specified Type#> in the protocol.

You might want to let the AdSeach class be generic, holding a generic typeholder which is used to specify (below, implicitly by inference) the typealias for the associatedtype of the DynamicContentFetcher protocol.

class AdSearch<U>: DynamicContentFetcher {
    // typealias T = U // infered
    var results = MutableObservableArray<U>()
    func content() -> MutableObservableArray<U> {
        return results
    }
}

struct DynamicAd {}
let dynamicAdSearch = AdSearch<DynamicAd>()

Upvotes: 5

Related Questions