![](/img/trans.png)
[英]Swift protocol with constrained associated type error “Type is not convertible”
[英]Use protocol with constrained associated type as property in Swift
我正在嘗試實現具有關聯類型的數據源協議
protocol DataSourceCompatible {
associatedtype CellModel
func cellModelForItem(at indexPath: IndexPath) -> CellModel
}
協議AddressBookViewModelType
繼承自基本協議,並將關聯的值約束到另一個協議
protocol AddressBookViewModelType: class, DataSourceCompatible where CellModel == AddressBookCellModelType {
}
AddressBookViewModel
是AddressBookViewModelType
協議的具體實現
class AddressBookViewModel: AddressBookViewModelType {
func cellModelForItem(at indexPath: IndexPath) -> AddressBookCellModelType {
let contact = sectionedContacts[indexPath.section][indexPath.row]
return AddressBookCellModel(contact: contact)
}
}
代碼可以正常編譯,但是當我在viewcontroller上將viewmodel聲明為屬性時,編譯器將失敗, 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
}
...
}
我記得看到類型擦除可能解決了這個問題,但是我對類型擦除的概念並不熟悉。 有沒有辦法解決這個問題?
更新:
這里的AddressBookCellModelType和AddressBookCellModel有什么關系?
這是實現協議的結構。
protocol AddressBookCellModelType {
var name: String { get }
var photo: UIImage? { get }
var isInvited: Bool { get }
}
struct AddressBookCellModel: AddressBookCellModelType {
....
}
您是否嘗試過僅將其用作通用名稱,例如警告/錯誤提示:
class AddressBookViewController<T: AddressBookViewModelType> : UIViewController {
private var viewModel: T!
func configure(viewModel: T) {
self.viewModel = viewModel
}
...
}
您需要使用變量T
的屬性初始化控制器,以便可以推斷出類型。
為了擴展我在注釋中的問題,查看此代碼看起來很靈活,而無需添加AddressBookCellModelType
或AddressBookViewModelType
,這也將擺脫麻煩,同時仍然可以在DataSourceCompatible
上通用。
// This protocol is fine and very useful for making reusable view controllers. Love it.
protocol DataSourceCompatible {
associatedtype CellModel
func cellModelForItem(at indexPath: IndexPath) -> CellModel
}
// No need for a protocol here. The struct is its own interface.
// This ensures value semantics, which were being lost behind the protocol
// (since a protocol does not promise value semantics)
struct AddressBookCellModel {
var name: String
var photo: UIImage?
var isInvited: Bool
}
// AddressBookViewModel conforms to DataSourceCompatible
// Its conformance sets CellModel to AddressBookCellModel without needing an extra protocol
class AddressBookViewModel: DataSourceCompatible {
let sectionedContacts: [[AddressBookCellModel]] = []
func cellModelForItem(at indexPath: IndexPath) -> AddressBookCellModel {
return sectionedContacts[indexPath.section][indexPath.row]
}
}
class AddressBookViewController: UIViewController {
private var viewModel: AddressBookViewModel!
func configure(viewModel: AddressBookViewModel) {
self.viewModel = viewModel
}
}
通過這種方式,可以實現通用的VC,而無需引入所需的更多組件:
class DataSourceViewController<DataSource: DataSourceCompatible>: UIView {
private var viewModel: DataSource.CellModel!
func configure(viewModel: DataSource.CellModel) {
self.viewModel = viewModel
}
}
let vc = DataSourceViewController<AddressBookViewModel>()
只是Swift規范,您不能使用“具有關聯類型的協議”作為類型聲明。 原因是編譯器在編譯時不知道關聯的類型實際上是什么,這違反了Swift的“類型安全性”。
解決方案是使用您所說的類型擦除器,或者使類型通用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.