Как использовать быстрые KeyPaths в универсальных методах - PullRequest
0 голосов
/ 31 марта 2019

Я пытаюсь провести рефакторинг нескольких общих методов в моем классе Repository, который создает закрытие завершения для вызова API.Основное изменение, которого я хочу добиться, - реализовать новый тип Swift 5 Result и немного обобщить завершение.

Предыдущая (и рабочая версия) выглядит следующим образом:

private func getAllCompletion<T>(_ type: T.Type, completion: (() -> Void)?) throws -> ((GetResourceRequest<T>) -> Void) where T: Codable{
        switch type {
        case is Acronym.Type:
            return getCompletion(for: \Repository.acronyms, completion: completion) as! ((GetResourceRequest<T>) -> Void)
        case is User.Type:
            return getCompletion(for: \Repository.users, completion: completion) as! ((GetResourceRequest<T>) -> Void)
        case is Category.Type:
            return getCompletion(for: \Repository.categories, completion: completion) as! ((GetResourceRequest<T>) -> Void)
        default:
            throw ErrorFactory.invalidType(type).error
        }
    }

private func getCompletion<T>(for keyPath: ReferenceWritableKeyPath<Repository, [T]>, completion: (() -> Void)?) -> ((GetResourceRequest<T>) -> Void) {
        return {[weak self] resourceRequest in
            switch resourceRequest {
            case .success(let resource):
                self?[keyPath: keyPath] = resource
            case .failure:
                break
            }
            completion?()
        }
    }

Я произвел рефакторинг и попытался обобщить его немного таким образом:

private func getCompletion<ResourceType>(_ type: ResourceType.Type, completion: ((Error) -> Void)?) -> ((Result<ResourceType, Error>) -> Void) where ResourceType: Codable{
        switch type {
        case is [Acronym].Type:
            getCompletion(for: \Repository.acronyms, with: completion)
        case is [User].Type:
            getCompletion(for: \Repository.users, with: completion)
        case is [Category].Type:
            getCompletion(for: \Repository.categories, with: completion)
        default:
            let error = ErrorFactory.invalidType(type).error
            completion?(error)
        }

    }

private func getCompletion<ResourceType>(for keyPath: ReferenceWritableKeyPath<Repository, ResourceType>, with completion: ((Error?) -> Void)?) -> ((Result<ResourceType, Error>) -> Void) {
        return { [weak self] result in
            switch result {
            case .success(let resource):
                self?[keyPath: keyPath] = resource
                completion?(nil)
            case .failure(let error):
                completion?(error)
            }
        }
    }

Iне могу понять, что мне не хватает, но это не скомпилируется.Сообщение, которое я получаю для всех трех вызовов getCompletion(for:completion), выглядит следующим образом:

Cannot convert value of type 'ReferenceWritableKeyPath<Repository, [Acronym]>' to expected argument type 'ReferenceWritableKeyPath<Repository, _>'

Заранее благодарю за ответы и извиняюсь, если мне не хватает чего-то действительно очевидного.

Я также знаю, что было бы намного лучше использовать решение на основе Rx вместо дополнений, но для этого конкретного примера я не хотел использовать сторонние библиотеки, потому что хотел посмотреть, могу ли я управлятьбез них:).

...