Using Associatedtype in a Delegate Protocol for a Generic Type

Using associatedtype in a delegate protocol for a generic type

You could remove the associated type requirement from your protocol and use a generic function game instead:

protocol GamePointsDelegate {
func game<B>(_ game: Game<B>, didSetPoints points: Int)
}

So you can use the code of your Game class as it is but the downside is that the class which conforms to the protocol has to handle all Boards.

Using delegates on generic protocol

This is not possible to use generic protocols. Use concrete type or usual protocol instead. You have to declare concrete T outside of those abstractions

For instance, this should work:

class MyType<T> {

weak var delegate: UsingGenericProtocol<T>? // First error

var t: T

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

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

}
class UsingGenericProtocol<T>: GenericProtocol {
let myType: MyType<T>
typealias type = T

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

func funca(component: T) {

}
}

let instance = UsingGenericProtocol<Int>(t: 0)

How to use a generic protocol as a delegate?

For protocols that have associated types, the compiler needs to know exactly what type the conforming object is.
To make that happen, we can either use a conforming concrete type directly or use the protocol as a generic constraint. The actual types that are being referred to won’t be known unless we provide some additional context.
So you can give the FirebaseService a concrete type:

weak var delegate: ChildViewController?

That will work but maybe this is not what you want.
Please read this excellent article by John Sundell:
Why can’t certain protocols, like Equatable and Hashable, be referenced directly?

Can't use property of a protocol type once protocol has associated type

As the error message suggest, make it a generic type instead. Also the typealias declaration is pointless since you don't use it and it has no connection with the protocol. Connect T with the associated type of the protocol bye adding a where condition to the class declaration (I also renamed T to DataType)

class BaseRepository<DataType, Delegate: BaseRepositoryDelegate> where Delegate.dataType == DataType{
typealias dataType = DataType
var delegate: Delegate?
var tag: Int?

private(set) public var data = [DataType]()
private(set) public var currentPage = 0
private(set) public var totalCount = 0

init(delegate: Delegate, tag: Int? = nil) {
self.delegate = delegate
self.tag = tag
}
}

Simple example

struct RepoDelegate: BaseRepositoryDelegate {
typealias dataType = Int

func didUpdateData(allData: [Int], currentPage: [Int], totalDataCount: Int, tag: Int?) {}
func didGetError(error: ApiError) {}
}

let delegate = RepoDelegate()
let repo = BaseRepository(delegate: delegate, tag: nil)

To use this for a sub-class you need to define for what data type and delegate type you are extending the base class

SpecificRepository: BaseRepository<MySpecificType, SpecificRepoDelegate>

where we match the type for the delegate

struct SpecificRepoDelegate: BaseRepositoryDelegate {
typealias dataType = MySpecificType
//...
}

How can assing generic (associated type require) protocol as delegate to any controller?

I handle the situation like that.

final class AnotherController<T: MessageProtocol> where T.MessageType == String {

weak var messagerDelegate: T?

...
}

And if I want to create anotherController instance programmatically, I created like that.

let instance = AnotherController<MainController>(frame: CGRect.zero)
instance.delegate = self
...

Because of MainController is comfortable with MessageProtocol from

extension MainController: MessageProtocol{}

Probably it's not common case but worked for me.

Is there information somewhere on Swift protocol associatedtype using `=` versus `:`?

The = and the : are two independent parts of an associated type declaration, rather than being mutually exclusive. This is the full syntax of protocol associated type declaration:

attributes(opt) 
access-level-modifier(opt)
'associatedtype'
typealias-name
type-inheritance-clause(opt)
typealias-assignment(opt)
generic-where-clause(opt)

The : TypeName part is the type-inheritance-clause, and the = TypeName is the typealias-assignment.

: TypeName constrains what type the associated type can be, namely that it must inherit/conform to TypeName. This is why : SomeManagerDelegate didn't work in your case. You are saying that SomeManager.DelegateType must be some kind of SomeManagerDelegate, but for Manager, this is not true - Manager.delegate is of type ManagerDelegate, which is a totally unrelated protocol. Even if it were SomeManagerDelegate, it wouldn't work either because protocols don't conform to themselves.

= TypeName sets a default type for the associated type. If the compiler cannot infer what the type the associated type for a conformance should be and you didn't say it explicitly it either, it will use that type instead. But in your case, this fact didn't really matter. What actually caused your code to work, wasn't the addition of = SomeManagerDelegate, but the removal of the constraint : SomeManagerDelegate. You are no longer constraining what type the associated type should be (it can be anything!), so for Manager, the associated type can now be inferred to be ManagerDelegate. Note that you don't have to explicitly say:

typealias DelegateType = ManagerDelegate

In fact, you can totally remove = SomeManagerDelegate and just say:

associatedtype DelegateType

so it is far from the truth that the = is "the only thing keeping it together".

This = TypeName syntax doesn't seem very well documented. Here's a related Swift forums post.

Using protocol with generic data type to pass data between screens

What you need to do is to make the second view controller generic using the protocol and limit the type of objects being used (or held) by the class conforming to ListDataHolder

This can be done in the declaration of the view controller

class SecondViewController<Holder: ListDataHolder>: UIViewController where Holder.T == ToDo

then your method onAddClicked will work as is.

Swift protocol with associatedtype error

You have a couple of options.

Firstly you can use a specific type of FooDelegate, like SomeFoo:

class Bar {
//In Bar instance runtime ,it will call delegate to do something...
var delegate: SomeFoo!
}

Or you can make Bar generic and define what type of Item the delegate needs:

class Bar<F> where F: FooDelegate, F.Item == Int {
//In Bar instance runtime ,it will call delegate to do something...
var delegate: F!
}

How can I implement a generic class that conforms to a protocol with associated type?

You can't use a protocol with associated type the same way as you would use normal protocol, but you can use DataSource as type constraint in SomeClass in this way:

class SomeClass<T, D:DataSource> where D.DataItem == T {
private let dataSource:D

init(dataSource: D) {
self.dataSource = dataSource
}
func getSomeStuff() -> T {
return dataSource.getItem(at: 0)
}
}

let sc = SomeClass<Int, DataSourceAgent>(dataSource: DataSourceAgent())
print(sc.getSomeStuff())


Related Topics



Leave a reply



Submit