iOS 앱 개발 부트캠프/TIL

TIL 15일차 - 뷰컨트롤러와 프로토콜

iosstudyletsgo 2024. 10. 4. 18:24

저번에 네비게이션 컨트롤러와 뷰컨트롤러를 실습하면서 해결 못하던 문제를 해결했다. 네비게이션 바의 Back 버튼을 누른 뒤 다시 두번째 화면으로 넘어가면 뷰컨트롤러에 값이 초기화되어 없어져있던 문제 말이다.

delegate를 사용해 두번째 뷰컨트롤러에서 입력받은 데이터를 첫번째 뷰컨트롤러로 넘기려고 했던건데, 이 네비게이션 바의 Back 버튼은 segue를 호출하지 않고 그냥 화면을 닫기만 하기 때문에 데이터를 넘기지 않은 것이라고 한다.

그래서 이 Back 버튼을 눌렀을때 값을 넘겨주는 코드를 썼다.

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        if self.isMovingFromParent { //네비게이션 바의 Back 버튼을 눌렀을때만 실행
            delegate?.passDataBack(secondDataList)
        }
    }

viewWillDisapper는 viewDidLoad나 viewWillAppear 같은 뷰의 라이프 사이클 중 하나로, 이름 그대로 뷰가 사라지기 전에 호출되는 메서드라고 한다. 이 메서드를 override 하여 화면을 떠나기 전에 원하는 작업(첫 화면으로 데이터 전달하기)을 수행하는 것이다.

isMovingFromParent는 뷰컨트롤러가 네비게이션 스택에서 pop될 때, 즉 뒤로 이동할 때 true를 반환한다고 한다. 따라서 if문과 같이 쓰인 이 부분 코드는 사용자가 back 버튼을 눌렀을때 delegate를 통해 데이터를 전달하는 역할을 한다.

첫번째 화면에서 1111을 입력하고, 두번째 화면에서 222와 333, 그리고 다시 back 버튼을 눌러 아무 값도 입력하지 않아 No data received가 출력되고 다시 두번째 화면에서 값이 잘 입력되었다.

이렇게 하니 생각했던 대로 동작은 잘 하는데, 그냥 써야한다니까 쓰던 delegate와 protocol에 대해 좀 더 자세히 알고싶어졌다.

delegate?.passDataBack 부분은 delegate를 통해 입력받은 데이터들을 저장한 배열인 secondDataList를 passDataBack 메서드에 넘기는 건 알겠는데, delegate는 뭘까? 저번에 쓴 코드를 살펴보면

protocol SecondViewControllerDelegate: AnyObject {
    func passDataBack(_ dataList: [String])
}
class SecondViewController: UIViewController, UITableViewDelegate, 
UITableViewDataSource {

weak var delegate: SecondViewControllerDelegate?

이런 부분이 있다. 배열을 매개변수로 받는 passDataBack(_ :)이라는 메서드를 SecondViewControllerDelegate라는 이름의 protocol로 정의하고, 이 프로토콜을 채택한 delegate라는 변수를 선언했다.

그리고 첫번째 뷰컨트롤러에서

    func passDataBack(_ dataList: [String]) {
        self.dataList = dataList
    }

이런 식으로 프로토콜에서 정의한 passDataBack 메서드를 구현하였다.

이렇게 하면 두번째 뷰컨트롤러에서 delegate를 통해 passDataBack 메서드를 호출할 때 delegate?.passDataBack(secondDataList)로 썼는데 이때 실제로 호출되는 것은 첫번째 뷰컨트롤러에서 구현한 메서드이다.

이런 식으로 프로토콜을 선언하면 그 프로토콜을 채택해 따르는 객체는 필수적으로 프로토콜을 선언할 때 정의한 특정 메서드나 속성을 구현해야 한다. 이 코드에서는 passDataBack이 그 부분이다. 

전에 찾아봤던 super를 쓰던 상속 개념과 비슷해 보이는데, 상속은 클래스 간의 관계를 설정해 구조적 계층을 만드는 것이고 프로토콜은 인터페이스를 정의해 여러 객체가 일관된 방식으로 동작하도록 하는데 중점을 둔다고 한다.

그래서 왜 상속으로 데이터를 주고 받는 게 아니라 굳이 프로토콜을 쓴 걸까? 싶어서 더 찾아보니 상속은 부모 - 자식간의 결합도가 높아 변경 사항이 서로에게 영향을 주지만 프로토콜은 독립적으로 동작하기 때문에 변경 사항의 영향을 덜 받는다고 한다.

내가 실습한 코드에서 프로토콜을 쓴 건 첫번째 화면에서 두번째 화면으로 넘어갔다 다시 첫번째 화면으로 넘어오는 식으로 동작하기 때문이다. 데이터를 주고받는 과정에서 두 개의 뷰컨트롤러가 서로 연결 되는데, 이 과정에서 안전을 위해 독립성을 유지하고자 한 것이다.

상속으로 데이터를 주고 받았다면 첫번째 뷰컨트롤러나 두번째 뷰컨트롤러에서 코드가 수정 되었을 때, 양쪽 뷰컨트롤러가 서로 영향을 받아 에러가 나거나 원치 않는 데이터의 변화가 일어날 수도 있다. 또 두번째 화면은 첫번째 화면으로 돌아가면 사리지기 때문에 데이터 저장에 대해 좀 더 복잡한 방법을 써야 할 수도 있다.

프로토콜로 구현함으로써 뷰컨트롤러가 서로 데이터를 주고받는 과정에서 첫번째 뷰컨트롤러에선 passDataBack 메서드를 구현해 저장하는 일만 하고, 두번째 뷰컨트롤러에선 delegate(위임)를 통해 데이터를 전달만 하는 일을 하기 때문에 다른 뷰컨트롤러끼리 독립성을 유지하며 안전하게 데이터를 전달하고 전달 받을 수 있었던 것이다.

'iOS 앱 개발 부트캠프 > TIL' 카테고리의 다른 글

TIL 17일차 - 간단한 비디오 앱 도전1  (2) 2024.10.08
TIL 16일차 - 자료 구조  (1) 2024.10.07
TIL 14일차 - 네비게이션 컨트롤러와 테이블뷰  (1) 2024.10.02
TIL 13일차  (2) 2024.09.30
TIL 12일차  (2) 2024.09.27