Добро пожаловать в заключительную часть раздела Укрощение массивных контроллеров в iOS. Настоятельно рекомендуется прочитать Часть 1 и Часть 2 этой серии, прежде чем продолжить эту статью.

В предыдущих статьях мы выделили источник данных элемента управления UITableView в отдельный класс под названием «ShoppingListDataSource». Это переместило все функции источника данных из ShoppingListViewController в назначенные классы для источников данных. Эта техника очень помогла нам уменьшить размер контроллера и расставить вещи по своим местам.

Когда пользователь выбирает список покупок, он / она отправляется на экран продуктовых товаров, где отображаются все связанные элементы из выбранного списка покупок. Это означает, что нам нужно создать отдельный источник данных для продуктовых товаров. GroceryItemsDataSource будет выглядеть точно так же, как ShoppingListDataSource, с той лишь разницей, что GroceryItemsDataSource будет работать с элементами типа GroceryItem вместо ShoppingList, как показано на снимке экрана ниже:

Альтернативный метод - создать общий источник данных и классы диспетчера данных, которые будут работать для всех классов.

Универсальный UITableViewDataSource и менеджеры данных:

Общий TableViewDataSource не будет зависеть от типа сущности класса, ячейки или диспетчера данных / поставщика данных, связанного с объектом. Объявление UITableViewDataSource показано ниже:

class TableViewDataSource<CellType :UITableViewCell, Entity :ManagedObjectType>: NSObject, UITableViewDataSource, FetchedResultsDataProviderDelegate {

Как видите, TableViewDataSource - это общий класс, в котором вы можете передать тип ячейки и сущность. Поскольку мы работаем с CoreData, наши классы сущностей наследуются от настраиваемого протокола ManagedObjectType, который является нашим настраиваемым типом. Инициализатор TableViewDataSource принимает все необходимые параметры, как показано ниже:

init(cellIdentifier :String,tableView :UITableView,dataProvider :FetchedResultsDataProvider<Entity>,cellConfigurationHandler :(CellType,Entity) -> ()) {
self.cellIdentifier = cellIdentifier
self.cellConfigurationHandler = cellConfigurationHandler
self.dataProvider = dataProvider
self.tableView = tableView
super.init()
}

Следует отметить один интересный момент: параметр dataProvider, который также является универсальным типом FetchedResultsDataProvider. Давайте посмотрим на код в ShoppingListTableViewController, который объявляет источник данных и поставщики данных.

private var dataSource :TableViewDataSource<ShoppingListTableViewCell,ShoppingList>!
private var dataProvider :FetchedResultsDataProvider<ShoppingList>!

Затем мы инициализируем свойства dataSource и dataProvider соответствующей информацией.

override func viewDidLoad() {
super.viewDidLoad()
self.dataProvider = FetchedResultsDataProvider(managedObjectContext: self.managedObjectContext)
self.dataSource = TableViewDataSource(cellIdentifier: “ShoppingListTableViewCell”, tableView: self.tableView, dataProvider: self.dataProvider, cellConfigurationHandler: { (cell :UITableViewCell, shoppingList :ShoppingList) in
cell.textLabel?.text = shoppingList.title
})
self.tableView.dataSource = self.dataSource
}

Все остальное остается прежним! Мы только что заменили конкретные реализации ShoppingList общей реализацией. Это означает, что теперь нам не нужно создавать отдельные реализации для GroceryItemsDataSource и GroceryItemsDataManager.

На этом этапе вы, должно быть, думаете, что универсальная реализация - лучший способ решить все ваши проблемы. К сожалению, серебряной пули нет. У вас определенно будет намного меньше кода, если вы выберете общий источник данных и поставщиков данных, но за это придется заплатить. Стоимость - это степень гибкости, которую вы получите при написании общих реализаций. Родовое означает ... родовое! Это означает, что ваша реализация применяется к нескольким классам. Если участвующие классы немного расходятся, ваша общая реализация должна быть обновлена, чтобы учесть эти изменения.

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

Какой путь вы выберете при написании отдельных источников данных и поставщиков данных и почему?

[Скачать проект]