Ako použiť architektúru MVC na zabránenie preťaženia kontroléra?
sobes.tech AI
Odpoveď od AI
MVC (Model-View-Controller) v iOS často vedie k "hrubým" kontrolérom kvôli umiestneniu biznis logiky a logiky zobrazenia v nich. Na riešenie tohto problému možno použiť nasledujúce prístupy:
-
Presun logiky zobrazenia do View: Vytvorenie vlastných
UIViewalebo buniek tabuľky/koliek, ktoré sú zodpovedné za zobrazovanie údajov a spracúvajú základné akcie používateľa (napríklad stlačenia tlačidiel v bunke). Kontrolér iba konfiguruje View potrebnými údajmi.class MyCustomView: UIView { private let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) addSubview(label) // Nastavenie constraints a pod. } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(with text: String) { label.text = text } // Spracovanie udalostí UIControlEvents, napríklad cez addTarget } -
Presun biznis logiky do Modelu alebo samostatných Service Objects: Vytvorenie tried, ktoré sú zodpovedné za konkrétne operácie (napríklad práca so sieťou, databázou, validácia údajov). Kontrolér deleguje vykonanie týchto úloh týmto objektom.
class UserService { func fetchUsers(completion: @escaping ([User]?, Error?) -> Void) { // Logika sieťového dopytu } } class ProfileViewController: UIViewController { private let userService = UserService() override func viewDidLoad() { super.viewDidLoad() userService.fetchUsers { users, error in // Aktualizácia UI na základe získaných údajov alebo chyby } } } -
Použitie Data Source a Delegate Protocols: Implementácia protokolov
UITableViewDataSource,UICollectionViewDataSource,UITableViewDelegate,UICollectionViewDelegatev samostatných triedach, nie v samotnom kontroléri. Kontrolér bude iba vlastniť inštancie týchto tried.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čítanie údajov a ich odovzdanie do dataSource.update(users:) } } -
Použitie Coordinator Pattern: Vytvorenie samostatných objektov zodpovedných za navigáciu medzi obrazovkami. Kontroléry vedia iba to, že je potrebné prejsť na ďalší krok, ale nie to, ktorý kontrolér bude nasledovať.
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() // Nastavenie delegáta, dataSource a pod. navigationController.pushViewController(usersVC, animated: false) } func showUserDetails(user: User) { let userDetailsVC = UserDetailsViewController(user: user) navigationController.pushViewController(userDetailsVC, animated: true) } }
Tieto prístupy umožňujú odľahčiť kontrolér, čím sa stáva "tenším" a sústredí sa na riadenie životného cyklu View a koordináciu interakcie medzi Model a View, nie na vykonávanie celej logiky aplikácie.