не знаю как получить результат завершения - PullRequest
0 голосов
/ 21 апреля 2019

У меня проблемы с использованием результата обработчика завершения.Я получаю эту ошибку "Невозможно преобразовать значение типа '()' в ожидаемый тип аргумента"

struct SearchCollectionViewModel {
    let name: String
    let previewURL: String?
    var image:UIImage?
    let dataController = DataController()
}

extension SearchCollectionViewModel {
    init(with result: Result) {
        self.name = result.trackName
        self.previewURL = result.previewURL
        if let url = result.previewURL {
            let imgData = preview(with: url, completion: { data -> Data? in
                guard let data = data as? Data else { return nil }
                return data
            })
            self.image = UIImage(data: imgData)
        }
    }

    private func preview(with url: String, completion: @escaping (Data) -> Data?) {
        dataController.download(with: url) { data, error  in
            if error == nil {
                guard let imageData = data else { return }
                DispatchQueue.main.async {
                    _ = completion(imageData)
                }
            }
        }
    }
}

1 Ответ

0 голосов
/ 21 апреля 2019

Пара наблюдений:

  1. Вы не можете «вернуть» значение, которое извлекается асинхронно через экранирующее закрытие.

  2. Определение закрытия(Data) -> Data? говорит, что закрытию не только будет передано Data, извлеченное для изображения, но что закрытие само вернет что-то обратно к preview.Но это явно не так (отсюда и необходимость _, как в _ = completion(...)).Я бы посоветовал вам изменить это значение на (Data?) -> Void (или использовать шаблон Result<T, U>).

  3. Я бы предложил переименовать ваш тип Result, так как есть общеизвестный универсальныйвызывается Result<Success, Failure> для возврата .success(Success) или .failure(Failure).Это паттерн, который мы использовали некоторое время, но он также официально представлен в Swift 5.См. SE-0235 .

    Ваша кодовая база может иметь свой собственный тип Result, но позже это приведет к путанице, если и когда вы начнете принимать это соглашение Result<T, U>.

  4. Вы действительно не должны инициировать асинхронный процесс из init, а вместо этого вызывать метод для этого.

  5. Лично япереведите преобразование в UIImage в DataController, например

    extension DataController {
        func downloadImage(with url: URL, completion: @escaping (UIImage?, Error?) -> Void) {
            let task = URLSession.shared.dataTask(with: url) { data, _, error in
                let image = data.flatMap { UIImage(data: $0) }
                completion(image, error)
            }
            task.resume()
        }
    }
    

Итак, я могу предложить вам что-то вроде:

class SearchCollectionViewModel {
    let name: String
    let previewURL: String?
    let dataController = DataController()
    var image: UIImage?

    init(with result: Result) {
        self.name = result.trackName
        self.previewURL = result.previewURL
    }
}

extension SearchCollectionViewModel {
    func preview(with url: String, completion: @escaping (UIImage?) -> Void) {
        guard let urlString = previewURL, let url = URL(string: urlString) else {
            completion(nil)
            return
        }

        dataController.downloadImage(with: url) { [weak self] image, error in
            DispatchQueue.main.async {
                self?.image = image
                completion(image)
            }
        }
    }
}
...