Sobes.tech
Middle+

Hoe gebruik je de MVC-architectuur om overbelasting van de controller te voorkomen?

sobes.tech AI

Antwoord van AI

MVC (Model-View-Controller) in iOS leidt vaak tot "dikke" controllers vanwege het plaatsen van businesslogica en presentatie-logica erin. Om dit probleem op te lossen, kunnen de volgende benaderingen worden gebruikt:

  • Verplaats de presentatie-logica naar View: Maak aangepaste UIView of tabel-/collectie-cellen die verantwoordelijk zijn voor het weergeven van gegevens en het afhandelen van basisgebruikersacties (bijvoorbeeld knopdrukken binnen de cel). De controller configureert alleen de View met de benodigde gegevens.

    class MyCustomView: UIView {
        private let label = UILabel()
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            addSubview(label)
            // Instellingen voor constraints etc.
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func configure(with text: String) {
            label.text = text
        }
    
        // Afhandeling van UIControlEvents, bijvoorbeeld via addTarget
    }
    
  • Verplaats businesslogica naar Model of aparte Service Objects: Maak klassen die verantwoordelijk zijn voor specifieke operaties (bijvoorbeeld netwerkverkeer, database, gegevensvalidatie). De controller delegeert het uitvoeren van deze taken aan deze objecten.

    class UserService {
        func fetchUsers(completion: @escaping ([User]?, Error?) -> Void) {
            // Logica voor netwerkverzoek
        }
    }
    
    class ProfileViewController: UIViewController {
        private let userService = UserService()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            userService.fetchUsers { users, error in
                // UI bijwerken op basis van ontvangen gegevens of fout
            }
        }
    }
    
  • Gebruik Data Source en Delegate Protocols: Implementeer UITableViewDataSource, UICollectionViewDataSource, UITableViewDelegate, UICollectionViewDelegate in aparte klassen, niet in de controller zelf. De controller bezit alleen instanties van deze klassen.

    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
            // Gegevens laden en doorgeven aan dataSource.update(users:)
        }
    }
    
  • Pas het Coordinator Pattern toe: Maak aparte objecten die verantwoordelijk zijn voor navigatie tussen schermen. Controllers weten alleen dat ze naar de volgende stap moeten gaan, niet welk controller dat precies is.

    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()
            // Instellen van delegate, dataSource etc.
            navigationController.pushViewController(usersVC, animated: false)
        }
    
        func showUserDetails(user: User) {
            let userDetailsVC = UserDetailsViewController(user: user)
            navigationController.pushViewController(userDetailsVC, animated: true)
        }
    }
    

Deze benaderingen helpen om de controller te ontlasten, waardoor deze "dunner" wordt en zich meer richt op het beheren van de levenscyclus van de View en de coördinatie tussen Model en View, in plaats van de volledige logica van de applicatie uit te voeren.