Протоколно-ориентированная загрузка файлов
Недавно я посмотрел этот доклад ( ссылка, см. Раздел " Сеть") и решил сделать несколько замечаний в программировании, ориентированном на протокол. Поэтому я подумал об этом простом примере: View Controller для отображения списка файлов. Конечно, протокол-ориентированный способ, со следующими ограничениями:
FilesViewController
- содержит табличное представление & FilesTableViewAdapter
, Таблица просмотра делегата.FilesTableViewAdapter
- инициализируется с представлением таблицы & FilesProvider: Gettable
, так что в тестах могу вводить FilesProviderMock: Gettable
,FilesTableViewAdapter
является источником данных табличного представления и использует FilesProvider
для получения файлов.
final class FilesTableViewController: UIViewController {
var filesTableView: FilesTableView! { return view as! FilesTableView }
private var tableViewAdapter: FilesTableViewAdapter<FilesProvider>!
// MARK: Subclassing
override func loadView() {
view = FilesTableView(frame: UIScreen.main.bounds)
}
override func viewDidLoad() {
tableViewAdapter = FilesTableViewAdapter(filesTableView.tableView, provider: FilesProvider())
// Actually I would like to have this method in Adapter
// so that VC isn't handling networking.
tableViewAdapter.provider.get { result in
// result type: (Result<[File]>)
switch result {
case .success(let files): print(files)
case .failure(let error): print(error)
}
}
filesTableView.tableView.delegate = self
filesTableView.tableView.dataSource = tableViewAdapter
}
}
extension FilesTableViewController: UITableViewDelegate {
//
}
final class FilesTableViewAdapter<T: Gettable>: NSObject, UITableViewDataSource {
let provider: T
private let tableView: UITableView
init(_ tableView: UITableView, provider: T) {
self.tableView = tableView
self.provider = provider
super.init()
}
func problem() {
provider.get { result in
// Result type is (Result<T.T>) - :(
switch result {
case .success(let files): print(files)
case .failure(let error): print(error)
}
}
}
struct FilesProvider {
private let Files = [File]()
}
extension FilesProvider: Gettable {
func get(completionHandler: (Result<[File]>) -> Void) {
//
}
}
protocol Gettable {
associatedtype T
func get(completionHandler: (Result<T>) -> Void)
}
Я знаю, что зашел слишком далеко, обобщив этот фрагмент кода. Теперь я застрял, и у меня есть эти вопросы, на которые я не могу ответить сам:
- Как сделать это ориентированным на протокол способом с сетевым кодом в классе, отличном от VC (скажем, Adapter)?
- Как сделать его легко тестируемым и расширяемым в будущем?