Jak využít architekturu MVC k zabránění přetížení kontroléru?
sobes.tech AI
Odpověď od AI
MVC (Model-View-Controller) v iOS často vede k "tlustým" kontrolerům kvůli umístění podnikové logiky a logiky prezentace do nich. Pro řešení tohoto problému lze použít následující přístupy:
-
Přesun logiky prezentace do View: Vytvoření vlastních
UIViewnebo buněk tabulky/sbírky, které jsou odpovědné za zobrazování dat a zpracování základních akcí uživatele (například stisknutí tlačítek uvnitř buňky). Kontroler pouze konfiguruje View potřebnými daty.class MyCustomView: UIView { private let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) addSubview(label) // Nastavení constraints atd. } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(with text: String) { label.text = text } // Zpracování událostí UIControlEvents, například přes addTarget } -
Přesun podnikové logiky do Modelu nebo samostatných Service objektů: Vytvoření tříd odpovědných za konkrétní operace (například práce se sítí, databází, validace dat). Kontroler deleguje provádění těchto úkolů těmto objektům.
class UserService { func fetchUsers(completion: @escaping ([User]?, Error?) -> Void) { // Logika síťového požadavku } } class ProfileViewController: UIViewController { private let userService = UserService() override func viewDidLoad() { super.viewDidLoad() userService.fetchUsers { users, error in // Aktualizace UI na základě získaných dat nebo chyby } } } -
Použití protokolů Data Source a Delegate: Implementace
UITableViewDataSource,UICollectionViewDataSource,UITableViewDelegate,UICollectionViewDelegatev samostatných třídách, nikoli v samotném kontroleru. Kontroler bude vlastnit pouze instance těchto tříd.class UsersTableViewDataSource: NSObject, UITableViewDataSource { private var users: [User] = [] func update(users: [User]) { self.users = users } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return users.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) let user = users[indexPath.row] cell.textLabel?.text = user.name return cell } } class UsersViewController: UIViewController { @IBOutlet weak var tableView: UITableView! private let dataSource = UsersTableViewDataSource() override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = dataSource // Načtení dat a předání do dataSource.update(users:) } } -
Použití Patternu koordinátora: Vytvoření samostatných objektů odpovědných za navigaci mezi obrazovkami. Kontrolery vědí pouze o tom, že je třeba přejít na další krok, ale nevědí, který kontroler bude následující.
protocol AppCoordinator: AnyObject { func start() func showUserDetails(user: User) } class MainAppCoordinator: AppCoordinator { private let navigationController: UINavigationController init(navigationController: UINavigationController) { self.navigationController = navigationController } func start() { let usersVC = UsersViewController() // Nastavení delegáta, dataSource atd. navigationController.pushViewController(usersVC, animated: false) } func showUserDetails(user: User) { let userDetailsVC = UserDetailsViewController(user: user) navigationController.pushViewController(userDetailsVC, animated: true) } }
Tyto přístupy pomáhají odlehčit kontroler, činí ho "tenčím" a soustředí se na správu životního cyklu View a koordinaci interakce mezi Model a View, nikoli na provádění celé logiky aplikace.