简体   繁体   中英

Swift Initialize struct based on typealias

I want my code to be as reusable as it can be. Writer and JsonProperties are Protocols that define plenty of the functionality the related objects require. JsonProperties conforms to Codable protocol, but I want to implement a custom method for Core Data implementation, through a Writer , the question is:

Can I initialize an object that implements a Writer protocol through the typealias of JsonProperties ?

Right now I'm getting this error:

Cannot convert value of type '[Model]' to expected argument type '[Model.WriterType.Model]'

Here's the code:

protocol Writer {
    associatedtype Model: JsonProperties
    ...
    init(in dataStack: DataStack)
}

struct GenericWriter<Model: JsonProperties>: Writer { ... }

protocol JsonProperties: Codable {
    associatedtype WriterType: Writer
    ...
}

struct ConversationProperties: JsonProperties {
    typealias WriterType = GenericWriter<Self>
    ...

}

The implementation I was looking for, but got the error was:

func networkFetch<Model: JsonProperties>(type: Model.Type) -> AnyPublisher<Bool, Error> {
    let writer = Model.WriterType(in: dataStack)
    ...
    var objects = [Model]()
    ...
    writer.insert(objects) <- Error here!

My guess this is not the correct implementation of the init() of a typealias struct.

The problem you're seeing stems from the fact that you not haven't constrained the associate type WriterType within JsonProperties .

Currently, it accepts any WriterType type conforming to Writer , regardless of what its Model is.

What you probably want is for the WriterType type to have its Model be the same as the type being conformed to JsonProperties protocol - so you need to constrain it:

protocol JsonProperties: Codable {
    associatedtype WriterType: Writer where WriterType.Model == Self
}

The insert method accepts a [Model] , where Model is the associated type of Writer .

writer is of type Model.WriterType where WriterType is a Writer , so writer.insert accepts Model.WriterType.Model . Here, the first Model is the generic parameter of networkFetch , whereas the second Model is the associated type of the Writer protocol.

However, you have created a [Model] . This Model refers to the generic parameter of networkFetch , not the associated type.

There is actually no guarantee that your generic parameter Model is the same type as Model.WriterTypeModel.Model . For example, I could do:

struct FooProperties: JsonProperties {
    typealias WriterType = GenericWriter<ConversationProperties>
}

And if I pass FooProperties.self to networkFetch , the generic parameter Model would be FooProperties , but Model.WriterType.Model would be ConversationProperties .

There are many ways to fix this.

  1. You can constrain the WriterType associated type to forbid me from creating a FooProperties in the first place:
protocol JsonProperties: Codable {
    associatedtype WriterType: Writer where WriterType.Model == Self
}
  1. You can constraint the generic parameter Model :
func networkFetch<Model: JsonProperties>(type: Model.Type) -> AnyPublisher<Bool, Error>
    where Model.WriterType.Model == Model {
  1. You can create an array of Model.WriterType.Model instead (this will not work if you are deserialising objects of type Model and putting them into this array)
var objects = [Model.WriterType.Model]()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM