Swift协议类型使用报错:需用'any'修饰TransactionListViewViewModelItemProtocol
问题分析与解决方案:Protocol作为类型使用需添加any关键字
问题场景
在实现Swift协议时触发编译错误,错误提示:Use of protocol 'TransactionListViewViewModelItemProtocol' as a type must be written 'any TransactionListViewViewModelItemProtocol'
相关代码
- 协议及实现结构体(
TransactionListViewViewModelItem.swift):
protocol TransactionListViewViewModelItemProtocol: Comparable { var transactionBookingDate: Date { get } var transactionPartnerDisplayName: String { get } } struct TransactionListViewViewModelItem: TransactionListViewViewModelItemProtocol { static func < (lhs: TransactionListViewViewModelItem, rhs: TransactionListViewViewModelItem) -> Bool { return lhs.transactionBookingDate < rhs.transactionBookingDate } static func == (lhs: TransactionListViewViewModelItem, rhs: TransactionListViewViewModelItem) -> Bool { return lhs.transactionBookingDate == rhs.transactionBookingDate } var transactionBookingDate: Date { transactionModel.transactionDetail.bookingDate.getTransactionDate() } var transactionPartnerDisplayName: String { transactionModel.partnerDisplayName } private let transactionModel: Transaction // MARK: - init init(transaction: Transaction) { transactionModel = transaction } }
- ViewModel中使用协议(
TransactionListViewViewModel.swift):
protocol TransactionListViewViewModelProtocol { init(fileName: String) var numberOfRows: Int { get } func transactionItem(at indexPath: IndexPath) -> TransactionListViewViewModelItemProtocol } class TransactionListViewViewModel: TransactionListViewViewModelProtocol { private var arrayOfTransactions: [TransactionListViewViewModelItemProtocol] = [] // MARK: - init required init(fileName: String) { fetchAllTransactionsModel(from: fileName) } /* rest code.... */ }
错误原因
从Swift 5.7版本开始,带有Self关联类型要求的协议(比如继承了Equatable/Comparable的协议,这两个协议都包含Self约束)作为类型使用时,必须显式添加any关键字标记为存在类型(existential type),明确告知编译器这是一个符合该协议的任意类型实例。
你的TransactionListViewViewModelItemProtocol继承了Comparable,自然带有Self关联类型要求,因此直接用协议作为类型会触发编译错误。
修复方案
将所有直接使用TransactionListViewViewModelItemProtocol作为类型的位置,替换为any TransactionListViewViewModelItemProtocol:
修改后的ViewModel协议代码:
protocol TransactionListViewViewModelProtocol { init(fileName: String) var numberOfRows: Int { get } func transactionItem(at indexPath: IndexPath) -> any TransactionListViewViewModelItemProtocol }
修改后的ViewModel类代码:
class TransactionListViewViewModel: TransactionListViewViewModelProtocol { private var arrayOfTransactions: [any TransactionListViewViewModelItemProtocol] = [] // MARK: - init required init(fileName: String) { fetchAllTransactionsModel(from: fileName) } /* rest code.... */ }
修改后即可通过编译。
内容的提问来源于stack exchange,提问作者Nupur Rawat
相关产品推荐
相关产品推荐

