swift - 如何获得具有完成和结果类型工作的泛型?
问题描述
我目前正在为两个数据库 API(领域和 Firestore)编写数据库访问类。为了精简代码,我尝试用泛型(#1)解决整个问题。不幸的是,它不起作用。我在哪里错过了重点?
我尝试定义关联类型(#2)并将它们设置在 RealmAccessStragy 类中。但是在这一点上,如果尝试通过 PersistenceController 访问协议,编译器会返回错误。
我很感激任何帮助!
方法#1
enum DataResult<T> {
case success(T)
case failure(Error)
}
protocol DataApiAccess: AnyObject {
func read<U, T>(primaryKey: U, completion: @escaping ((DataResult<T>) -> Void))
}
class RealmAccessStrategy {
...
func read<U, T>(primaryKey: U, completion: @escaping ((DataResult<T>) -> Void)) {
guard let realmObject = realmInstance.object(ofType: realmObjectType, forPrimaryKey: primaryKey) else {
completion(.failure(RealmAccessError.noObject))
return
}
completion(.success(realmObject)) // ERROR: Member 'success' in 'DataResult<_>' produces result of type 'DataResult<T>', but context expects 'DataResult<_>'
}
}
// Later implementation
class PersistenceController {
private let strategy: DataApiAccess
init(use: DataApiAccess) {
self.strategy = use
}
func load<U, T>(primaryKey: U, completion: @escaping ( (DataResult<T>) -> Void ) ) {
strategy.read(primaryKey: primaryKey, completion: completion)
}
}
错误:“DataResult< >”中的成员“成功”产生“DataResult”类型的结果,但上下文需要“DataResult< >”
方法#2
enum DataResult<T> {
case success(T)
case failure(Error)
}
protocol DataApiAccess {
associatedtype ReturnType
func read(primaryKey: PrimaryKeyType, completion: @escaping DataApiHandler<ReturnType>)
}
class RealmAccessStrategy: DataApiAccess {
...
// Typealias
internal typealias ReturnType = Object
func read(primaryKey: Any, completion: @escaping ((DataResult<Object>) -> Void)) {
guard let realmObject = realmInstance.object(ofType: realmObjectType, forPrimaryKey: primaryKey) else {
completion(.failure(RealmAccessError.noObject))
return
}
completion(.success(realmObject))
}
}
class PersistenceController {
private let strategy: DataApiAccess // ERROR: Protocol 'DataApiAccess' can only be used as a generic constraint because it has Self or associated type requirements
init(use: DataApiAccess) {
self.strategy = use
}
...
}
}
错误:协议“DataApiAccess”只能用作通用约束,因为它具有 Self 或关联的类型要求
解决方案
您不能设置可变的通用协议,但可以设置方法
下面的示例代码
为基本结果创建枚举:
enum DataResult<T> { case success(T) case failure(Error) }
///Set a protocol generic methods:
protocol DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: @escaping (DataResult<T>) -> Void)
}
class RealmAccessStrategy: DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: @escaping (DataResult<T>) -> Void) {
// Read data from database
}
}
class NetworkAccessStrategy: DataApiAccess {
func read<T: Codable>(primaryKey: PrimaryKeyType, completion: @escaping (DataResult<T>) -> Void) {
// Get data from request
}
}
class PersistenceController {
private let strategy: DataApiAccess
init(use: DataApiAccess) {
// Set dependency inversion for offline or online state
self.strategy = use
}
func foo() {
// TODO
//strategy.read(primaryKey: <#T##PrimaryKeyType#>, completion: <#T##(DataResult<Decodable & Encodable>) -> Void#>)
}
}
享受!
推荐阅读
- javascript - 使用节点和动态生成的 HTML 修改 HTML 文件
- database - 如何将 CSV 文件导入 DolphinDB?
- python - 打开和关闭 Firefox 浏览器的两个实例
- javascript - Node.js - 无法使用 $(this) 从 jquery 访问把手元素
- java - 为什么这个while循环与“and”运算符一起使用而不与“or”一起使用?
- keras - DepthwiseConv2D 和 SeparableConv2D 的区别
- c++11 - 无状态 Lambda 和私有成员
- node.js - 执行 http.get 的 Promise 返回“待处理”
- maven - 仅发布来自一个大项目的某些工件
- ios - 导致 MPNowPlayingInfoCenter 丢失状态的广告横幅