지난 글에서 deallocate가 되지 않게 하려고 parent coordinator가 child coordinators 프로퍼티를 가지게 하는 것을 알아보았다.
이 외에도 정석적인(?)방법으로 coordinator를 사용하면 여러가지 불편함이 있었다.
기존에는 parent가 child coordinators를 가지면서 ARC에 의해 자동으로 deallocated 되는 것을 방지했다.
이렇게 하지 말고 view와 coordinator간의 강한 참조를 만들어서 coordinator가 retain되게 해보자.
MVVM 상에서 다이어그램을 나타내면 다음 그림과 같이 나타낼 수 있다.
이렇게 구현을 한다면 view가 pop 되었을 때 view controller가 release되고, view model이 release되고 coordinator가 release된다.
coordinator의 마지막 참조가 끊긴 상황이라면 별도의 callback 코드 또는 다른 방법들을 취하지 않고도 (기존에는 child coordinators 프로퍼티에서 제거를 해주어야 했음) 자동으로 release시킬 수 있다.
이제 childCoordinators와 같은 프로퍼티는 필요가 없어졌다.
그저 weak
으로 선언한 presenter에 대한 참조만 있으면 된다.
class MainCoordinator: Coordinator {
private weak var navigationController = UINavigationController?
func start() {
...
}
}
extension Coordinator: ViewModelDelegate { ... }
// Coordinator와 연결을 위한 protocol
protocol ViewModelDelegate { ... }
// ViewController와 연결을 위한 protocol
protocol ViewModelType { ... }
class ViewModel: ViewModelType {
let delegate: ViewModelDelegate
}
ViewModel에서는 coordinator, view controller와 각각 소통할 수 있는 protocol을 만들어주면 된다.
중요한 점은, coordinator에 대한 참조가 strong이어야 한다는 것이다.
class ViewController: UIViewController {
let viewModel: ViewModelType
}
여기서도 마찬가지로 viewModel에 대한 참조가 strong이어야 한다.
이렇게 자동으로 deallocate가 가능하게 구현을 하면 coordinator를 release하기 위해서 코드를 작성하지 않아도 되고 따로 고려할 필요도 없어진다. 또한 iOS에서 화면을 dismiss 시키는 방법이 back button을 클릭하는 것 뿐만 아니라 스와이프 등의 다른 방법들도 있는데, 이렇게 dismiss시키는 방법에 구애받지 않을 수 있게 된다.
view가 dismiss 되어도 제대로 release가 되지 않는다면 coordinator가 retain되면서 메모리릭이 발생한다.
하지만 이는 childCoordinators를 사용하는 방법에도 발생할 수 있는 문제이고, 이 방법에서는 오히려 메모리릭을 찾기 더 어렵다. 또한 수동적으로 release를 시켜줘야하는데, 코드를 작성하다보면 이를 잊어버리고 놓치는 경우도 있을 수 있다.
따라서 Instruments, VM Debugging을 통해서 정상적으로 release가 되어서 메모리 릭이 발생하는지 확인을 하는 것이 중요하다.