Como usar a arquitetura MVC para evitar sobrecarregar o controlador?
sobes.tech IA
Resposta da IA
MVC (Model-View-Controller) no iOS frequentemente leva a controladores "pesados" devido à colocação de lógica de negócio e lógica de apresentação neles. Para resolver este problema, podem-se usar as seguintes abordagens:
-
Externalizar a lógica de apresentação na View: Criar
UIViewpersonalizados ou células de tabelas/coleções que sejam responsáveis por mostrar dados e lidar com ações básicas do utilizador (por exemplo, pressionar botões dentro da célula). O controlador apenas configura a View com os dados necessários.class MyCustomView: UIView { private let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) addSubview(label) // Configuração de constraints, etc. } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(with text: String) { label.text = text } // Manipulação de eventos UIControlEvents, por exemplo, via addTarget } -
Externalizar a lógica de negócio em Modelos ou objetos de Serviço separados: Criar classes responsáveis por operações específicas (por exemplo, trabalho com rede, base de dados, validação de dados). O controlador delega a execução dessas tarefas a esses objetos.
class UserService { func fetchUsers(completion: @escaping ([User]?, Error?) -> Void) { // Lógica de requisição de rede } } class ProfileViewController: UIViewController { private let userService = UserService() override func viewDidLoad() { super.viewDidLoad() userService.fetchUsers { users, error in // Atualização da UI com base nos dados recebidos ou erro } } } -
Utilização de Protocolos Data Source e Delegate: Implementar os protocolos
UITableViewDataSource,UICollectionViewDataSource,UITableViewDelegate,UICollectionViewDelegateem classes separadas, e não no controlador. O controlador apenas terá instâncias dessas classes.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 // Carregamento de dados e passagem para dataSource.update(users:) } } -
Aplicação do Padrão Coordinator: Criar objetos separados responsáveis pela navegação entre telas. Os controladores apenas sabem que precisam passar para o próximo passo, mas não qual controlador será o seguinte.
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() // Configuração do delegate, dataSource, etc. navigationController.pushViewController(usersVC, animated: false) } func showUserDetails(user: User) { let userDetailsVC = UserDetailsViewController(user: user) navigationController.pushViewController(userDetailsVC, animated: true) } }
Estas abordagens permitem descarregar o controlador, tornando-o mais "fino" e focado na gestão do ciclo de vida da View e na coordenação entre Model e View, e não na execução de toda a lógica da aplicação.