Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use protocol with constrained associated type as property in Swift

I'm trying to implement a datasource protocol with associated type

protocol DataSourceCompatible {
    associatedtype CellModel
    func cellModelForItem(at indexPath: IndexPath) -> CellModel
}

Protocol AddressBookViewModelType inherits from base protocol and constrains the associated value to another protocol

protocol AddressBookViewModelType: class, DataSourceCompatible where CellModel == AddressBookCellModelType {
}

AddressBookViewModel is a concrete implementation of AddressBookViewModelType protocol

class AddressBookViewModel: AddressBookViewModelType {
    func cellModelForItem(at indexPath: IndexPath) -> AddressBookCellModelType {
        let contact = sectionedContacts[indexPath.section][indexPath.row]
        return AddressBookCellModel(contact: contact)
    }
}

The code compiles fine, however when I declare the viewmodel as a property on my viewcontroller, the compiler fails with Protocol 'AddressBookViewModelType' can only be used as a generic constraint because it has Self or associated type requirements.

class AddressBookViewController: UIViewController {
    private var viewModel: AddressBookViewModelType!

    func configure(viewModel: AddressBookViewModelType) {
        self.viewModel = viewModel
    }
...
}

I remember seeing type erasure might solve the issue, but I'm not that familiar with type erasure concept. Is there a way to solve the issue?

Update:

How are AddressBookCellModelType and AddressBookCellModel related here?

It's a struct implementing a protocol.

protocol AddressBookCellModelType {
    var name: String { get }
    var photo: UIImage? { get }
    var isInvited: Bool { get }
}

struct AddressBookCellModel: AddressBookCellModelType {
 ....
}
like image 572
NikGreen Avatar asked Sep 13 '25 19:09

NikGreen


1 Answers

Have you tried just using it as a generic, like the warning/error says:

class AddressBookViewController<T: AddressBookViewModelType> : UIViewController {
    private var viewModel: T!

    func configure(viewModel: T) {
        self.viewModel = viewModel
    }
    ...
}

You'd need to initialise your controller with a property of variable T so the type can be inferred.

like image 198
regina_fallangi Avatar answered Sep 16 '25 07:09

regina_fallangi