본문 바로가기

MOBILE/ios

[iOS] segue 객체를 이용한 화면 전환 처리하기

ios 에서는 다양한 방식으로 화면을 전환할 수 있다. 크게 4가지 정도이다.

화면 전환 방법에 따라 이전 화면으로 돌아가는 방법도 달라진다.

 

화면 전환 방법

1. 뷰를 전환하기

2. 뷰 컨트롤러를 전환하기

3. 네비게이션 컨트롤러에 의한 화면 전환

4. 세그웨이에 의한 화면 전환

 

1. 뷰 자체를 전환하기

뷰 자체를 전환하는 방법은 하나의 뷰 컨트롤러 안에 루트 뷰 두개를 두고 전환한다. 하지만 이는 뷰 컨트롤러:루트뷰 = 1:1 이라는 MVC 패턴을 벗어나므로 좋지 않다. 또한 뷰 컨트롤러의 루트 뷰를 가져와서 올릴 수도 있지만 이 또한 뷰의 소속 컨트롤러는 무엇인지 모호해지기 때문에 좋지 않은 방식이다.

 

2. 뷰 컨트롤러를 전환하기

뷰 컨트롤러를 전환하는 방식은 가장 많이 쓰인다. 이미 present(_:animated:) 메소드는 여러곳에서 쓴 경험이 있을 것이다. 예를 들면 알림창이라던지

present 메소드를 활용한 화면 전환은 기존의 뷰 컨트롤러를 두고 그 위에 새로운 뷰 컨트롤러를 올려 화면을 덮는 방식이다.

뷰 컨트롤러의 포인터는 차례대로 presentation chain에 쌓이게 되고, 이전 화면으로 돌아갈 때는 이 포인터를 제거하는 것이다. 따라서  이전 화면으로 돌아갈 때, 이전 화면에 해당되는 뷰 컨트롤러를 present로 호출한다고 생각하기 쉽지만 이는 사실 이전 화면이 아니라 그냥 새로운 뷰 컨트롤러를 올리는 것이 된다.

따라서 dismiss(animated:completion:) 라는 unwind method를 사용해야 한다. 이때 이 메소드를 호출하는 주체는 이전 화면이 되어야 한다.

따라서 호출은 다음과 같이 이루어진다.

 

self.presentingViewController?.dismiss(previousView)

 

3. 네비게이션 컨트롤러에 의한 화면 전환하기

네비게이션 컨트롤러는 화면 전환이 발생하는 뷰 컨트롤러의 포인터를 stack으로 관리하여 접근한다. 이때의 stack을 navigation stack이라고 한다. 즉 네비게이션 컨트롤러는 뷰 컨트롤러가 아니로 뷰 컨트롤러를 관리하는 컨테이너 컨트롤러이다.

따라서 네비게이션 컨트롤러에 속해있는 화면을 전환하기 위해서는 당연하게도 네비게이션 컨트롤러를 통해서 전환해야 한다. 왜냐면 속해있으니까 ㅇㅇ 당연함

즉 navigation stack에 뷰 컨트롤러를 추가하고, 빼는 것을 통해 화면 전환을 할 수 있다.

또한 stack이므로 당연히 method의 이름에도 push, pop이 들어간다.

 

self.navigationController?.pushViewController(_:animated:)
self.navigationController?.popViewController(animated:)

 

 

4. 세그웨이에 의한 화면 전환하기

세그웨이(segue) 객체는 뷰 컨트롤러 사이의 연결 관계 및 화면 전환을 관리하는 역할을 한다.

이 객체를 사용하면 일반 버튼을 눌렀을 때 전환될 뷰 컨트롤러를 버튼과 직접 연결하여 화면 전환을 일으킬 수 있다.

 

이때 중요한 점은, segue는 일방통행이라는 것이다.

즉 한쪽으로만 이동하는 화면 전환이다. 따라서 segue 객체 하나로 wind method, unwind method 둘 다로 이용할 수 없다.

 

또한 segue는 스토리보드상의 연결 정보를 이용하여 전환 대상 뷰 컨트롤러의 인스턴스를 자동으로 만들어준다. 

즉 segue가 실행된 순간 출발지와 목적지가 정해지게 되고, 이에 대한 인스턴스들이 생성되어 segue 객체에 포인터로 설정된다.

source, destination으로 이를 찾아볼 수 있다.

 

segue는 출발점에 따라 크게 두가지로 구분된다.

 

segue의 구분

1. 메뉴얼 세그웨이 (Manual Segue)

2. 액션 세그웨이 (Action Segue or Trigger Segue)

 

이때 Action Segue는 버튼, table view cell 등의 이벤트가 출발점이 되고, Manual Segue는 출발점이 뷰 컨트롤러 그 자체이다. 이러한 Manual Segue를 실행하기 위해서는 performSegue(withIdentifier:sender:) 메소드와 함께 사용해야 한다.

이러한 segue를 자세하게 알아보자


Action Segue

터치 이벤트를 통해 세그웨이를 실행한다. 이때 button, table view cell 등 액션이 발생할 수 있는 요소와 segue는 직접 연결되어 있다.

 

segue를 연결하는 방법은 다음과 같다.

button, table cell 뭐든지 트리거를 실행할 수 있는 요소를 오른쪽 click하여 전환하고자 하는 뷰 컨트롤러로 끌고온다.

 

 

그 과정을 통하면 위와 같이 세그웨이의 타입을 선택할 수 있는 창이 뜬다.

이때 [Present Modally] 방식이 바로 present(_:animated:) method 와 같은 방식이다.

 

segue를 설정하고 나면 다음과 같이 segue 객체가 뷰 컨트롤러 사이에 생성된다.

 

segue 객체가 생겼다

 

이때 재밌는 방식은 바로 [Show] 방식이다.

이는 네비게이션 컨트롤러에 의한 화면 전환처럼 상단에 네비게이션 표시를 자동으로 줄 수 있다.

하지만 이렇게 네비게이션 바를 생성하고 싶다면 반드시 네비게이션 컨트롤러가 추가되어야 한다.

네비게이션 컨트롤러를 추가하지 않고 [Show] 방식을 선택했을 경우에는 [Present Modally]와 같은 방식으로 작동된다.

즉 [show] 방식이라 하더라도 네비게이션 바가 자동으로 추가되지 않는다.

 

navigation controller를 추가하고 Go2! 버튼은 [show] 방식으로 연결하면 다음과 같다.

 

 

하지만 다음처럼 navigation controller가 없다면 네비게이션 바가 자동으로 추가되지 않는다.

 

 

재밌다... 이런 디테일 알아가는 것은 비동기 처리나 알고리즘 로직만큼 재밌음

 

이렇게 Action segue는 버튼 등의 트리거를 누르면 무조건 화면을 전환한다.

하지만 조건이나 상황에 따라 화면을 이동하고 싶다면 어떻게 해야할까?

그때는 바로 Manual Segue를 활용한다.


Manual Segue

manual segue는 이름 그대로 뷰 컨트롤러 사이에서 연결되는 수동 세드웨이이다. 즉 세그웨이를 호출하는 메소드를 수동으로 실행해서 화면을 전환해야 한다. 이때 사용되는 메소드가 performSegue이다.

 

performSegue(withIdentifier:sender:)

 

첫번째 파라미터는 segue 객체의 식별자, 두번째 파라미터는 segue를 실행하는 객체를 전달한다.

manual segue의 특이한 점은 다음과 같이 바로 뷰 컨트롤러끼리 연결을 할때 Dock Bar를 사용하여 직접 연결해야 한다는것이다.

 

도크 바를 활용한 수동 연결

 

이렇게 연결하고 나면 segue 객체가 생성되는데 이때 식별자의 이름을 설정해야 performSegue에서 사용 가능하다.

 

segue를 생성했다면 이 segue가 실행될 순간을 정의한다.

지금은 버튼을 눌렀을 때 실행되도록 하기 위해서 action method를 정의한다.

이 안에 다음과 같이 메소드를 사용하면 manual segue 설정이 완료된다.

 

 


Unwind Method

앞서 이전 화면으로 돌아가기 위한 메소드를 unwind method라고 한다고 설명했다.

대표적으로 present 방식은 dismiss(animated:), 네비게이션 컨트롤러를 사용한다면 popViewController(animated:) 가 바로 unwind method이다.

 

그렇다면 manual segue는 unwind method를 어떻게 만들까?

segue가 일방통행이므로 wind segue 하나, unwind segue 하나 총 두개 만들어서 서로를 연결하면 될까?

결론적으로 이 방식은 틀렸다.

 

segue는 목적지가 되는 뷰 컨트롤러의 인스턴스를 자동으로 생성한다고 말했다. 이때 중요한 점은 "생성" 한다는 것이다. 즉 역방향의 세그웨이는 unwind 되지 않고 새로운 뷰 컨트롤러를 생성하는 것이다.

ios에서 뷰 컨트롤러는 singletone pattern이다. 즉 인스턴스가 하나 이상 존재해서는 안된다.

그렇다면 어떻게 unwind를 구현할까?

 

당연히 앞에서 배운 dismiss, popViewController 를 사용 가능하다.

또는 Dock Bar에서 Unwind Segue를 만들어서 Exit 아이콘과 연결하여 사용한다.

dock bar의 exit icon

 

이 아이콘을 unwind 트리거 대상 객체와 연결하면 다음과 같이 팝업 창이 뜬다.

 

 

이때 이 메소드는 반드시 "돌아가고자 하는 뷰 컨트롤러"에 정의되어 있어야 한다.

다음과 같이 반드시 UIStoryboardSegue를 파라미터로 받는 액션 메소드를 만들어 주면 된다.

이를 파라미터로 받아야 unwind segue로 인식하기 때문이다.

 

 

이제 연결하면 exit icon은 메소드를 인식하고 이를 찾아 Unwind Segue로 자동 생성 해준다.

이렇게 생성된 unwind segue는 present 방식, 네비게이션 컨트롤러 방식에 구분없이 실행된다. 즉 메모리에서 바로 dealloc 한다.


전처리 메소드 prepare(for :sender:)

segue가 실행되기 직전에 뭔가 특별한 처리를 해야한다면 어떻게 할까?

ios system은 segue를 실행하기 전에 특정한 메소드를 먼저 호출하도록 설계되어 있다. 이를 전처리 메소드라고 한다.

segue 실행 전에 값의 저장 또는 경고창 등의 처리를 할 때 유용하다.

 

전처리 메소드

 

이때 이 prepare 메소드는 누가 호출하는 것인가?

바로 시스템이 호출한다.

 

첫번째 매개변수는 sender, 즉 segue를 호출한 세그웨이 객체이다.

위에서 본 예시와 같이 segue는 여러개가 존재할 수 있다. 이때 어떤 segue가 왔을 때인지 구분해야 하기 때문에 매개변수로 전달된다.

 

두번째 매개변수는 segue를 실행하는 트리거 객체이다.

예를 들면 action segue라면 어떤 button 또는 table cell인지에 대한 정보를 가지고 있고, manual segue라면 뷰 컨트롤러가 전달된다.

다음과 같이 사용 가능하다.

 

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
	print("전처리 메소드")
}