delegate패턴과 메모리 누수
이번 글의 내용은 프로토콜을 사용할 때 weak
키워드를 제대로 사용하지 않아
메모리 누수가 발생하는 문제를 해결하는 방법에 대한 내용입니다.
델리게이트 패턴 사용
델리게이트 패턴을 사용하면 뷰컨트롤러에서 뷰에게 동작을 위임할 수 있습니다.
컬렉션뷰를 뷰컨트롤러가 아닌 뷰에 만들고 컨트롤도 위임할 수 있습니다.
이를 위해서는 delegate = self
와 같이 델리게이트를 설정해줘야 합니다.
HomeView
final class HomeView: BaseView {
// HomeViewController를 델리게이트로 위임
var delegate: HomeViewProtocol?
lazy var collectionView: UICollectionView = {...}()
...
}
extension HomeView: UICollectionViewDelegate, UICollectionViewDataSource {
...
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(#function)
// HomeViewProtocol를 통해 HomeViewController를 pop시킴
delegate?.didSelectItemAt(indexPath)
}
}
HomeViewController
protocol HomeViewProtocol {
func didSelectItemAt(_ indexPath: IndexPath)
}
final class HomeViewController: BaseViewController {
override func loadView() {
let view = HomeView()
view.delegate = self
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
}
deinit {
print(#function)
}
}
extension HomeViewController: HomeViewProtocol {
func didSelectItemAt(_ indexPath: IndexPath) {
navigationController?.popViewController(animated: true)
}
}
메모리 누수 문제
위 코드를 실행하게 되면 뷰컨트롤러가 메모리에서 해제되어야 할 시점에
deinit
이 호출되지 않고 메모리 사용량이 계속 늘어나는 문제가 발생합니다.
HomeViewController
에서 뒤로가기를 실행하고 다시 뷰컨트롤러에 진입하는
동작을 반복하면 메모리 사용량이 계속해서 증가하는 것을 확인할 수 있습니다.
HomeViewController
와 HomeView
가 서로를 강하게 가리키면서 강한 순환참조 사이클이 발생한 것입니다.
해결 방법
이 문제를 해결하기 위해서는 프로토콜에 AnyObject
로 제약을 걸어
class
에서만 프로토콜을 채택할 수 있도록 해야 합니다.
해결하기 위해서는 기존 코드에 weak
키워드를 추가해야 합니다.
HomeViewProtocol
에 클래스 제약 조건이 없기 때문에 weak
키워드를 사용할 수 없다고 합니다.
컴파일러님 그게 무슨말인가요?
weak
키워드는 class
의 RC카운트를 올려주지 않는 키워드입니다.
그러나 HomeViewProtocol
은 class
, struct
모두 채택할 수 있습니다.
따라서 컴파일러가 에러를 보내는 것입니다.
그럼 어떻게 해결해야 할까요?
protocol HomeViewProtocol: AnyObject {
func didSelectItemAt(_ indexPath: IndexPath)
}
프로토콜에 AnyObject
제약을 추가하여, 해당 프로토콜을 class
에서만 채택할 수 있도록 합니다.
그러면 정상적으로 작동 하는지 확인해 볼까요?
deinit
메서드가 정상적으로 호출되어 메모리 누수가 발생하지 않습니다.
결론
델리게이트 패턴을 사용할 때 weak
키워드를 제대로 사용하지 않아
메모리 누수가 발생하는 문제를 해결하는 방법에 대해 알아봤습니다.
HomeViewProtocol
에 클래스 제약 조건이 없기 때문에
weak
키워드를 사용할 수 없다는 컴파일러의 에러 메시지를 해결하기 위해서는,
프로토콜에 AnyObject
제약을 추가하여 해당 프로토콜을 class
에서만 채택할 수 있도록 합니다.
이렇게 해서 메모리 누수 문제를 해결할 수 있었고,
deinit
메서드가 정상적으로 호출되어 메모리 누수가 발생하지 않았습니다.
Uploaded by N2T