简体   繁体   中英

Protocol with associatedtype conformance with generic gives compiler error

I'm trying to make a DB mock to test some UI implementations, but compiler keeps giving me the following error: Type 'DBClientMock<T>' does not conform to protocol 'DBClient'

This is my code...

protocol DBClient {
    associatedtype Model
    func get(id: UUID, completion: @escaping ((Model?, Error?)) -> Void)
    func insert(_ model: Model, completion: @escaping (Error?) -> Void)
    func delete(_ model: Model, completion: @escaping (Error?) -> Void)
}

final class DBClientMock<T>: DBClient where T: Identifiable, T: Equatable {
    
    typealias Model = T
    
    private let queue: DispatchQueue
    private var modelDB = [T]()
    
    enum Error: Swift.Error {
        case notFound
    }
    
    init(queue: DispatchQueue = DispatchQueue.global()) {
        self.queue = queue
    }
    
    private func getModel(id: UUID) -> T? {
        let results = modelDB.filter({ $0.id as? UUID == id })
        guard results.count > 0 else { return nil }
        return results[0]
    }
    
    // Extension
    func get(id: UUID, completion: @escaping ((T?, Error?)) -> Void) {
        let record = getModel(id: id)
        queue.asyncAfter(deadline: .now() + .milliseconds(1500), execute: {
            if let model = record {
                completion((model, nil))
            } else {
                completion((nil, Error.notFound))
            }
        })
    }
    
    func insert(_ model: T, completion: @escaping (Error?) -> Void) {
        modelDB.append(model)
        queue.asyncAfter(deadline: .now() + .milliseconds(1000), execute: {
            completion(nil)
        })
    }
    
    func delete(_ model: T, completion: @escaping (Error?) -> Void) {
        modelDB.removeAll(where: { $0 == model })
        queue.asyncAfter(deadline: .now() + .milliseconds(800), execute: {
            completion(nil)
        })
    }
}

XCode: Version 12.4 (12D4e) Swift: 5.0

What am I doing wrong? Do I have to be more explicit with the generic type in some way? I tried replacing T with Model but had the same result.

Thanks for your help!

It doesn't conform because you declared another Error type inside the class, so everywhere where you use Error in the required methods, it uses DBClientMock.Error instead of the protocol-required Swift.Error .

Either rename DBClientMock.Error to something else, or change the Error in methods to Swift.Error , like below:

// Extension
func get(id: UUID, completion: @escaping (T?, Swift.Error?) -> Void) {
   //...
}

func insert(_ model: T, completion: @escaping (Swift.Error?) -> Void) {
   //...
}

func delete(_ model: T, completion: @escaping (Swift.Error?) -> Void) {
   //...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM