관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] UIStackView의 removeArrangedSubview 사용시 주의사항 (메모리릭, Memory Leak) 본문

iOS 응용 (swift)

[iOS - swift] UIStackView의 removeArrangedSubview 사용시 주의사항 (메모리릭, Memory Leak)

jake-kim 2023. 5. 11. 01:15

UIStackView의 removeArrangedSubview

  • 보통 UIStackView의 하위 뷰들을 제거할때 removeArrangedSubview를 통해 제거하는데, 이렇게만하면 memory leak이 발생
    • subviews에 접근하여 명시적으로 해당 뷰에서 removeFromSuperview()를 호출해줘야 제거가됨

ex) 메모리 릭 확인을 위해, 메모리에서 해제된경우 deinit에서 print문을 호출하는 뷰 정의

class MyView: UIView {
    init() {
        super.init(frame: .zero)
        backgroundColor = .yellow
        NSLayoutConstraint.activate([
            heightAnchor.constraint(equalToConstant: 200),
            widthAnchor.constraint(equalToConstant: 200),
        ])
    }
    required init?(coder: NSCoder) {
        fatalError()
    }
    
    deinit {
        print("DEINIT: MyView")
    }
}
  • 사용하는쪽에서 이 뷰를 UIStackView의 addArrangedSubview()로 삽입
stackView.addArrangedSubview(MyView())
  • 버튼을 눌렀을 때, removeArrangedSubview를 호출하는 코드를 놓고 이때 "DEINIT: MyView"가 호출되는지 확인
    • 결과 -> DEINIT이 호출안되며, 메모리릭이 발생
@objc private func tap() {
    stackView.arrangedSubviews
        .forEach(stackView.removeArrangedSubview(_:))
}
  • 만약 subviews에 접근하여 removeFromSuperview()를 호출시키면 DEINIT 프린트문 확인이 가능 (메모리해제 완료)
@objc private func tap() {
    let subviews = stackView.arrangedSubviews
    stackView.arrangedSubviews.forEach(stackView.removeArrangedSubview(_:))
    subviews.forEach { $0.removeFromSuperview() }
}

메모리 해제 완료

  • 공식 문서에서도 removeArrangedSubview()만 사용하면 뷰가 보일 수 있으니, 명시적으로 removeFromSuperview()를 사용하라는 문구가 존재

https://developer.apple.com/documentation/uikit/uiview/1622421-removefromsuperview

* 전체 코드: https://github.com/JK0369/ExStackView

* 참고

https://developer.apple.com/documentation/uikit/uiview/1622421-removefromsuperview

Comments