Search code examples
swiftgenericsfactory-pattern

Swift Generic Implementation of protocol throws error `Type does not conform to protocol`


I have 3 model classes:

protocol IncludedItem {
    var id: Int { get }
    var text: String { get }
}
protocol PrimaryItem {
    associatedtype Included: IncludedItem

    var id: Int { get }
    var canClose: Bool { get }
    var canDelete: Bool { get }
    var canSend: Bool { get }
    var includedItems: [Included] { get }
}
protocol QuoteItem {
    var id: Int { get }
    var isSelectable: Bool { get }
}

Then I want to use the factory pattern for Item creation. This is my factory protocol:

protocol QuoteItemFactory {
    associatedtype Item: PrimaryItem

    var delegate: QuoteItemFactoryDelegate? { get set }

    func create(item: Item) -> QuoteItem
}

And this is an implementation of the factory protocol:

class OrderQuoteItemFactory: QuoteItemFactory {

    weak var delegate: QuoteItemFactoryDelegate?

    func create<Item: PrimaryItem>(item: Item) -> QuoteItem {
        let viewModel = OrderQuoteViewModel(quote: item)
        viewModel.delegate = self

        return DefaultQuoteItem.quote(id: item.id, viewModel: viewModel)
    }
}

But then I always get the following error: Type 'OrderQuoteItemFactory' does not conform to protocol 'QuoteItemFactory'.

What am I doing wrong? I know if I use it like this:

class OrderQuoteItemFactory<Item: PrimaryItem>: QuoteItemFactory {

    weak var delegate: QuoteItemFactoryDelegate?

    func create(item: Item) -> QuoteItem {
        let viewModel = OrderQuoteViewModel(quote: item)
        viewModel.delegate = self

        return DefaultQuoteItem.quote(id: item.id, viewModel: viewModel)
    }
}

I know that using it like this will work perfectly. But I'm wondering why I can't use the generic with the function declaration.


Solution

  • What if you change your factory protocol to this?

    protocol QuoteItemFactory {
    
        var delegate: QuoteItemFactoryDelegate? { get set }
    
        func create<Item: PrimaryItem>(item: Item) -> QuoteItem
    
    }
    

    I noticed (at least from your example) that you don't really need an associatedType, so you could just make the function itself generic, instead of the protocol.