Ответ
Многие классы UIKit, созданные в эпоху MVC, демонстрируют нарушения SOLID из-за высокой связности и многофункциональности.
1. UIViewController — нарушение SRP (Принцип единственной ответственности)
- Проблема: «Massive View Controller» совмещает в себе:
- Управление жизненным циклом view.
- Бизнес-логику и обработку данных.
- Навигацию и логику переходов.
- Работу с делегатами таблиц/коллекций.
- Решение: Выделение ответственностей в отдельные объекты (Presenter, Interactor, Router, ViewModel).
2. UITableViewDataSource / UICollectionViewDataSource — нарушение OCP (Принцип открытости/закрытости)
- Проблема: Для изменения логики отображения ячеек (например, другой порядок секций) необходимо изменять код существующих методов
numberOfSections,cellForRowAt. - Решение: Использование архитектурных подходов (Compositional Layout, Diffable Data Source) или паттерна «Спецификация» для инкапсуляции логики секций и ячеек.
3. Неявные зависимости — нарушение DIP (Принцип инверсии зависимостей)
- Проблема: Прямое использование синглтонов и глобальных объектов.
class ProfileViewController: UIViewController { func saveUser() { // Нарушение DIP: прямая зависимость от конкретной реализации (CoreData) let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext // ... } } - Решение: Внедрение зависимости через протокол (интерфейс).
protocol DatabaseService { func save(user: User) }
class ProfileViewController { let database: DatabaseService // Зависимость от абстракции init(database: DatabaseService) { self.database = database } }
**4. Крупные делегаты — нарушение ISP (Принцип разделения интерфейсов)**
* **Проблема:** Протокол `UIScrollViewDelegate` содержит множество методов (`scrollViewDidScroll`, `scrollViewWillBeginDragging` и т.д.). Класс вынужден подписываться на весь протокол, даже если нужен один метод.
* **Решение:** Разделение на более мелкие протоколы (на практике достигается через необязательные методы в Objective-C, но логически проблема остаётся). Ответ 18+ 🔞
Ну слушай, вот смотри, эти старые UIKit-классы — они же как дед в деревне, который и печку топит, и корову доит, и забор чинит, и ещё в карты играет. Один на всё село, блядь. И вроде работает, но если он свалится — пиздец всему хозяйству. Так и тут.
1. UIViewController — это же просто ёбаный монстр, нарушение SRP в чистом виде
- В чём пиздец: Этот типок пытается быть всем сразу. Он как швейцарский нож, который и отвертка, и пила, и открывалка, но когда им пытаешься консервы открыть — хуй сломаешь. Он и вьюшкой рулит, и данные тащит, и по экранам прыгает, и таблицы настраивает. Массивный View Controller, сука! Одна ответственность? Да их там овердохуища!
- Что делать: Разделять этого франкенштейна. Вынести бизнес-логику в Interactor, отображение данных в Presenter или ViewModel, навигацию в Router. Пусть каждый занимается своим ебаным делом.
2. UITableViewDataSource — классическое нарушение OCP, ёпта
- В чём пиздец: Хочешь поменять логику секций или ячеек? Добро пожаловать в ад, блядь. Лезешь в методы
numberOfSectionsиcellForRowAtи начинаешь там костыли пилить. Код закрыт для расширения, но открыт для модификации — ровно наоборот, сука, от того, что нужно. - Что делать: Использовать Compositional Layout и Diffable Data Source — они уже более умные. Или паттерн «Спецификация», чтобы логику секций и ячеек инкапсулировать в отдельные объекты. Не лезть каждый раз в кишки старого кода.
3. Неявные зависимости — это пиздец, нарушение DIP
- В чём пиздец: Прямое обращение к синглтонам и глобальным объектам — это как ходить по охуенно тонкому льду. Смотри, какой ужас:
class ProfileViewController: UIViewController {
func saveUser() {
// Вот она, зависимость, блядь! Прямой выстрел в колено.
// Ты привязан к AppDelegate и CoreData намертво. Хуй отрефакторишь.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// ...
}
}
- Что делать: Внедрять зависимости через протоколы, ёбана! Зависить от абстракции, а не от конкретной реализации.
protocol DatabaseService {
func save(user: User)
}
class ProfileViewController {
let database: DatabaseService // А вот так — красиво. Зависим от интерфейса.
init(database: DatabaseService) { self.database = database } // Инжектим через инит.
}
Теперь можно подсунуть любую базу данных, хоть CoreData, хоть Realm, хоть файлик — контроллеру похуй.
4. Крупные делегаты — нарушение ISP, ебать мои старые костыли
- В чём пиздец: Берём
UIScrollViewDelegate. Методов там — дохуя. А тебе нужен только один,scrollViewDidScroll. Но подписываешься ты на весь протокол, и Xcode тебе подсказывает все остальные 15 методов, которые тебе нахуй не сдались. Интерфейс не разделён, ты вынужден тащить на себе весь этот груз. - Что делать: В Objective-C спасали необязательные методы, но логически-то проблема остаётся. Хорошая практика — выносить логику делегата в отдельный объект, который реализует только нужные методы. Или использовать современные замыкания (closures) там, где это возможно. Не городить огород из ненужного кода.
Короче, UIKit — это как старый, проверенный Запорожец. Едет, гремит, но чтобы сделать из него нормальную тачку, нужно половину узлов выкинуть и переделать. SOLID-принципы — это как инструкция по этому апгрейду.