首页 > 解决方案 > 如何获得具有完成和结果类型工作的泛型?

问题描述

我目前正在为两个数据库 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 或关联的类型要求

标签: swift

解决方案


您不能设置可变的通用协议,但可以设置方法

下面的示例代码

  • 为基本结果创建枚举:

    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#>)
        }


    }

享受!


推荐阅读