ios - 如何使用通用协议作为委托?
问题描述
我有一个用于解析获取的数据的通用协议:
protocol DataParseDelegate: AnyObject {
associatedtype FetchResult
func didFetchData(data: FetchResult?, error: Error?)
}
extension DataParseDelegate {
func didFetchData(data: FetchResult?, error: Error?) {
// process data
}
}
它位于解析为某种类型的视图控制器中:
class ParentViewController<T>: UIViewController {}
class ChildViewController: ParentViewController<DataModel>, DataParseDelegate {
typealias FetchResult = DataModel
override func viewDidLoad() {
super.viewDidLoad()
FirebaseService.delegate = self
FirebaseService.shared.db.downloadData()
}
func didFetchData(data: DataModel?, error: Error?) {
// process data
}
}
我正在使用委托将获取的数据传递给视图控制器:
class FirebaseService {
static let shared = FirebaseService()
var db: Firestore! {
let settings = FirestoreSettings()
Firestore.firestore().settings = settings
let db = Firestore.firestore()
return db
}
weak var delegate: DataParseDelegate?
func downloadData() {
let first = db?.collection("myData")
.order(by: "date")
.limit(to: 8)
first?.getDocuments(completion: { [weak self] (snapshot: QuerySnapshot?, error: Error?) in
// handle errors
self?.delegate?.didFetchData(data: nil, error: error)
// parse the snapshot into DataModel
self?.delegate?.didFetchData(data: dataModel, error: nil)
}
}
}
我收到以下错误:
协议 'DataParseDelegate' 只能用作通用约束,因为它具有指向委托的 Self 或关联类型要求:
weak var delegate: DataParseDelegate?
我尝试使用以下内容而不是associatedtype
:
protocol DataParseDelegate: AnyObject {
func didFetchData<T>(data: [T]?, error: Error?)
}
extension DataParseDelegate {
func didFetchData<T>(data: [T]?, error: Error?) {
// process data
}
}
但是,我收到一条错误消息:
无法推断通用参数“T”
关于代表:
first?.getDocuments(completion: { [weak self] (snapshot: QuerySnapshot?, error: Error?) in
self?.delegate?.didFetchData(data: nil, error: error) <-----
}
解决方案
对于具有关联类型的协议,编译器需要确切地知道符合对象的类型。为了实现这一点,我们可以直接使用符合要求的具体类型,也可以使用协议作为通用约束。除非我们提供一些额外的上下文,否则不会知道所引用的实际类型。所以你可以给 FirebaseService 一个具体的类型:
weak var delegate: ChildViewController?
这会起作用,但也许这不是你想要的。请阅读 John Sundell 的这篇优秀文章: 为什么不能直接引用某些协议,例如 Equatable 和 Hashable?
推荐阅读
- python-3.x - python3模拟成员变量多次获取
- java - 选择 no 后 showInputDialog 显示次数过多
- python - 为什么这段代码没有使用 re 模块的编译和搜索功能返回电话号码列表?
- linux - 防止将颜色从 cli 复制到 txt 文件
- python - 如何在同一行打印两个列表中的项目?
- c# - 用于删除和创建文件夹的 SSIS 脚本
- powershell - 使用带有 2 列的 powershell 在 CSV 文件上输出序列号和 MAC 地址
- git - Git 与 github 的通信非常慢
- php - 模拟 api 调用就像在 flash 中发生的一样
- java - Java 中未处理的异常错误,即使使用 try-catch