Kako koristiti MVC arhitekturu da izbegnemo preopterećenje kontrolera?
sobes.tech АИ
Одговор од АИ
MVC (Model-View-Controller) u iOS često dovodi do "debelih" kontrolera zbog smeštanja poslovne logike i logike prikaza u njih. Za rešavanje ovog problema, mogu se koristiti sledeći pristupi:
-
Premeštanje logike prikaza u View: Kreiranje prilagođenih
UIViewili ćelija tabele/kolekcije koje su odgovorne za prikaz podataka i obradu osnovnih akcija korisnika (npr. pritisci na dugmad unutar ćelije). Kontroler samo konfiguriše View potrebnim podacima.class MyCustomView: UIView { private let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) addSubview(label) // Podešavanje constraints itd. } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(with text: String) { label.text = text } // Obrada događaja UIControlEvents, na primer putem addTarget } -
Premeštanje poslovne logike u Model ili posebne Service objekte: Kreiranje klasa koje su odgovorne za specifične operacije (npr. rad sa mrežom, bazom podataka, validacijom podataka). Kontroler delegira izvršenje ovih zadataka tim objektima.
class UserService { func fetchUsers(completion: @escaping ([User]?, Error?) -> Void) { // Logika mrežnog zahteva } } class ProfileViewController: UIViewController { private let userService = UserService() override func viewDidLoad() { super.viewDidLoad() userService.fetchUsers { users, error in // Ažuriranje UI na osnovu dobijenih podataka ili greške } } } -
Korišćenje protokola Data Source i Delegate: Implementacija
UITableViewDataSource,UICollectionViewDataSource,UITableViewDelegate,UICollectionViewDelegateu posebnim klasama, a ne u samom kontroleru. Kontroler će samo posedovati instance ovih klasa.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 // Učitavanje podataka i prosleđivanje u dataSource.update(users:) } } -
Primena Pattern-a Koordinator: Kreiranje posebnih objekata koji su odgovorni za navigaciju između ekrana. Kontroleri znaju samo da treba da pređu na sledeći korak, ali ne i koji će kontroler biti sledeći.
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() // Podešavanje delegate, dataSource itd. navigationController.pushViewController(usersVC, animated: false) } func showUserDetails(user: User) { let userDetailsVC = UserDetailsViewController(user: user) navigationController.pushViewController(userDetailsVC, animated: true) } }
Ovi pristupi pomažu da se rastereti kontroler, čineći ga "tanijim" i fokusirajući se na upravljanje životnim ciklusom View i koordinaciju interakcije između Model i View, a ne na izvršavanje cele logike aplikacije.