[iOS] 화면 전환

민니·2022년 3월 29일
0

iOS

목록 보기
1/22

화면 전환에 대하여 공부해 봅시다 😀


  • 화면 전환 방식
  • 뷰 컨트롤러 직접 호출 방식
  • 네비게이션 컨트롤러 이용 방식
  • segue way 이용 방식


화면 전환 방식

화면 전환 방식은 쉽게 4가지로 구분할 수 있음.

  • view controller의 view 위에 다른 view를 가져와 바꿔치기
  • view controller에서 다른 view controller을 호출하여 화면 전환하기
  • navigation controller 이용하기
  • segue way 이용하기

첫 번째 방식인 <view controller의 view 위에 다른 view를 가져와 바꿔치기>는 하나의 뷰 컨트롤러가 2개 이상의 루트 뷰를 관리해야 하고, 뷰를 제어할 책임을 지는 컨트롤러가 모호해진다는 단점이 있음.
또한 고려할 부분이 많기 때문에, view를 이용한 화면 전환은 되도록이면 사용하지 말 것 ❌

그 외 3가지 방식은 전환할 화면의 인스턴스를 생성하고 호출하여 기존 화면에 덮는 방식임.




화면 전환 기법 1 - 뷰 컨트롤러 직접 호출에 의한 화면 전환

뷰 컨트롤러를 직접 호출해서 화면을 표시한다 하여 프레젠테이션(presentation)방식이라고도 함.

프로젝트를 생성할 시 자동으로 만들어지는 View Controller을 보면, UIViewController 클래스를 상속받음을 알 수 있음.

프레젠테이션 방식은 이 클래스에 정의된 present 메소드를 이용

present(<새로운 뷰 컨트롤러 인스턴스>, animated: <애니메이션 여부>


화면 전환이 완료되는 시점에 특정 로직을 실행해 주려면,

present(_: animated: completion: )

메소드를 이용.
마지막 매개변수는 실행 구문을 클로저나 함수 형식으로 입력받아, 화면 전환이 완전히 끝난 후 호출해 줌.

Q. 그냥 present 메소드 다음에 코드를 이어서 작성하면 안 될까?
A. 불행하게도 present 메소드 다음에 작성된 구문이 화면 전환이 끝난 다음에 실행된다는 보장을 할 수가 없음 ㅜ.ㅜ,,


이전 화면으로 돌아가려면?

dismiss(animated:)

메소드를 사용해 주기.
이전 화면으로 돌아가는 것이기 때문에 뷰 컨트롤러의 인스턴스를 인자값으로 설정해 주지 않아도 됨.
화면 복귀가 처리되었을 때 실행하고 싶은 로직이 있다면, 마찬가지로

dismiss(animated: completion: )

메소드를 사용.

  • 화면 복귀를 할 때 주의해야 할 점은, 기존 화면이 새로운 화면 위에 올라오는 것이 아니라, 기존 화면 위에 덮었던 새 화면을 걷어낸다는 점!
    걷어낸 화면의 뷰 컨트롤러 객체는 OS에 의해 메모리에서 해제됩니다.

이때, 화면을 걷어내는 주체는 자기 자신이 아니라 자신을 띄우고 있는 이전 뷰 컨트롤러임.

다음 화면의 뷰 컨트롤러가 이전 뷰 컨트롤러에게 화면을 내려달라고 요청하는 방식으로 화면 복귀가 이루어지는데, 화면을 내려달라고 요청할 대상을 참조할 포인터가 presentingViewController이다.

따라서, 복귀 메소드를 호출하는 대상 인스턴스는 self가 아니라 self.presentingViewController 임



present 메소드를 이용 예제

첫 번째 화면 구성: "첫 번째 화면" label과 다음 화면으로 넘어갈 수 있는 버튼
두 번째 화면 구성: "두 번째 화면" label과 다음 화면으로 넘어갈 수 있는 버튼

화면 전환하기

두 번재 뷰 컨트롤러가 선택된 상태에서, 인스펙터 영역에서 StoryBoardID 항목을 찾아 SecondVC라고 입력!
(다른 것으로 입력해도 상관없음)

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func tapPresentNext(_ sender: UIButton) {
        // 이동할 뷰 컨트롤러 객체를 참조
        guard let uvc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") else {
        	return
        }
        
        //인자값으로 뷰 컨트롤러 인스턴스를 넣고 프레젠트 메소드 호출
        self.present(uvc, animated: true)
    }
    
}

self.storyboard?.instantiateViewController(withIdentifier: "SecondVC")

새로 표시할 뷰 컨트롤러를 스토리보드로부터 읽어와 인스턴스화하는 부분.
입력된 StoryboardID와 일치하는 뷰 컨트롤러를 찾아, 인스턴스를 생성하고 이 값을 받아옴

present 메소드를 사용할 때, 전환할 대상이 될 인스턴스(instantiateViewController 메소드를 이용하여 만들어둔 uvc 상수)를 인자값으로 넘겨주면 화면 전환이 이루어짐.

화면 복귀하기

  • SecondViewController.swift 라는 파일을 만들어 주고, 클래스와 뷰 컨트롤러를 연결하기
    (cocoa touch class source로 파일로 만들면 됨)
  • 둘을 연결해 주는 방법은 StoryboardID를 입력했을 때와 같이 custom class - class 에 SecondViewController을 입력

두 번째 뷰 컨트롤러와 SecondViewController 클래스가 연결 완료!



SecondViewController에 뒤로 가기 버튼 액션을 설정해 주기

import UIKit

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        
    }
    

    @IBAction func tapPresentUnwind(_ sender: UIButton) {
        self.presentingViewController?.dismiss(animated: true)
    }
    

}

이전 화면으로의 복귀를 진행 완료





화면 전환 기법2 - Navigation controller 이용


navigation controller 의 특성

  • 뷰 컨트롤러의 특별한 종류
  • 계층적인 성격을 띠는 콘텐츠 구조를 관리하기 위한 컨트롤러
  • 앱의 내비게이션을 표시해 줄 수 있는 내비게이션 바 내장
  • 화면 전환이 발생하는 뷰 컨트롤러들의 포인터를 스택으로 관리
  • 관리하는 역할로, 직접 콘텐츠를 담고 화면을 구성하지는 않음
  • 다른 뷰 컨트롤러들을 포함
  • 이 컨트롤러가 제어하는 모든 뷰 컨트롤러에 navigation bar 생성

Root View Controller

내비게이션 컨트롤러는 항상 콘텐츠 계층 구조의 시작점 역할을 하는 뷰 컨트롤러와 함께 다니는데, 이를 루트 뷰 컨트롤러라고 함.

앞서 정리한 것처럼, navigation controller은 화면에 현재 표시되고 있는 뷰 컨트롤러들을 navigation stack을 이용하여 관리한다..

스택 형식으로 쌓았을 때,
가장 아래에 있는 첫 번째 뷰 컨트롤러 => 루트 뷰 컨트롤러,
최상위에 있는 마지막 뷰 컨트롤러 => 현재 화면에 표시되고 있는 뷰 컨트롤러


스택을 이용하여 관리하는 Navigation controller 답게, 다음화면으로 넘어갈 때는 pushViewController 메소드 이용.

pushViewController(_: animated: )

마찬가지로 화면을 복귀할 때는,

popViewController(animated: )

메소드를 사용.



내비게이션 컨트롤러 추가하기

내비게이션 컨트롤러를 추가하는 방식 2가지

  • 오브젝트 라이브러리에서 내비게이션 컨트롤러를 추가하기
    Root View Controller 도 자동으로 추가됨

  • Embed In 기능 이용하기

뷰 컨트롤러를 선택하여 활성화한 뒤,
Editor - Embed Int - Navigation Controller 을 선택하면,

스토리보드에서 선택된 뷰 컨트롤러를 루트 뷰 컨트롤러로 삼아, 내비게이션 컨트롤러만 추가됨.
내비게이션 바가 생성.


화면 전환하기

프레젠테이션 방식을 이용할 때와 동일하게, 뷰 컨트롤러를 만들어 주고 label과 버튼을 만들어 준 뒤,
StoryboardID 항목에 SecondVC를 입력

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func tapNCNext(_ sender: UIButton) {
        //두 번째 뷰 컨트롤러 인스턴스를 가져온다.
        
        guard let uvc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") else {
            return
        }
        
        //화면 전환
        self.navigationController?.pushViewController(uvc, animated: true)
    }
}

pushViewController 메소드는 기술적 관점에서 내비게이션 스택 최상위에 뷰 컨트롤러 객체 uvc를 추가하는 것이지만, 사용자들에게는 화면을 전환하는 결과로 나타남.
pushViewController 메소드는 호출하는 대상이 내비게이션 컨트롤러임.

코드를 실행하여 다음 화면으로 버튼을 누르면,

무사히 다음 화면으로 넘어왔는데, 프레젠테이션 방식과 다른 점은 바로 자동으로 back 버튼이 만들어진다는 것.

화면 복귀하기

마찬가지로, SecondViewController 클래스를 만들어 준 뒤 두 번째 화면 뷰 컨트롤러와 연결해 주기.

이전 화면 버튼의 액션을 만들어 주고, popViewController 메소드를 사용하면 화면 복귀가 이루어진다.

import UIKit

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    

   
    @IBAction func tapNCUnwind(_ sender: UIButton) {
        self.navigationController?.popViewController(animated: true)
    }
    
}




화면 전환 기법 - Segue Way 이용

앞서 프로그래밍 방식으로 화면을 전환하는 방법에 대하여 알아보았음.
지금부턴 스토리보드의 화면 전환 기능을 이용해 보겠음!

세그웨이

  • 스토리보드에서 뷰 컨트롤러 사이의 연결 관계 및 화면 전환을 관리
  • 화면 - 화면 연결을 위해 아무런 소스코드도 필요로 하지 않음
  • 뷰 컨트롤러 사이에 연결된 화살표로 표시
  • 한쪽 방향으로만 흐르는 화면 전환
  • 액션 세그웨이: 버튼 등이 출발점인 경우
  • 매뉴얼 세그웨이: 출발점이 뷰 컨트롤러 자체인 경우

액션 세그웨이

main에 추가되어 있는 뷰 컨트롤러 외에 하나를 더 추가해 준 후에, 앞선 예제들처럼 레이블과 버튼을 추가해 준다.

버튼을 선택하고 두 번째 뷰 컨트롤러 전체에 드래그 하면, 세그웨이 연결 옵션이 뜨는데,
여기서 Present Modally가 앞서 배운 present(:animated:) 메소드를 이용한 화면 전환과 같은 기능을 함.



Present Modally를 선택하면

화면과 화면 사이에 화살표가 생기는데, 이 화살표가 바로 두 개의 뷰 컨트롤러가 세그웨이로 연결되었다는 표시

이처럼 pushViewController 메소드처럼 이용하려면 내비게이션 컨트롤러를 생성해 준 뒤, 옵션을 Show 로 선택하기.


화면 복귀

화면 복귀를 하고 싶으면, 앞서 배운 화면 복귀용 메소드를 똑같이 이용

  • present Modally 옵션 - dismiss(animated:)
  • show 옵션 - popViewController(animated:)

매뉴얼 세그웨이

  • 매뉴얼 세그웨이는 해당 이벤트만 발생하면 자동으로 실행되는 액션 세그웨와 달리 뷰 컨트롤러와 뷰 컨트롤러 사이에 연결되는 수동 실행 세그웨이
  • 매뉴얼 세그웨이는 수동으로 실행해야 하므로 소스코드에서 메소드를 호출해야 합니다.

peformSegue(withIdentifier: <세그웨이 식별자>, sender: <세그웨이 실행 객체>)

매뉴얼 세그웨이를 연결할 때는 뷰 컨트롤러와 뷰 컨트롤러 사이를 직접 연결

도크바에서 view controller을 선택한 후, 두 번째 뷰 컨트롤러로 드래그한 뒤, Present Modally를 선택

화살표 마크가 추가되면, 세그웨이의 Identifier을 ManualWind로 입력해 보자.

세그웨이를 실행하기 위해 첫 번째 화면에 다음 화면으로 버튼을 만든 뒤 앞서 언급한 performSegue 메소드를 작성

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func tapManualNext(_ sender: UIButton) {
        //세그웨이 실행
        self.performSegue(withIdentifier: "ManualWind", sender: self)
    }
    
}

화면을 복귀하기 위해서는 똑같이 앞에서 언급했던 메소드들을 이용하면 됨. 😀



이처럼 세그웨이를 이용하여 화면을 전환하는 방식은 구현이 쉽고 간단하지만, 전환 과정에서 제어할 수 있는 것이 제한됨.

그렇다면, 세그웨이를 이용하여 화면을 전환하는 과정에서 특별한 처리가 필요할 땐 어떻게 해야 할까?

다행히도 코코아 터치 프레임워크는 세그웨이가 실행되기 전에 전처리 메소드를 호출하도록 설계되어 있음.
이를 이용하면 화면을 전환하기 전에 필요한 처리가 가능하다.

prepare(for segue: UIStoryboardSegue, sender: Any?) { //code}

사실 전처리 메소드는 UIViewController 클래스에 이미 정의되어 있는 메소드이므로, 사용하고 싶을 땐 오버라이드하여 작성하면 됨.









출처: 꼼꼼한 재은씨의 Swift

0개의 댓글