날쌘 개발자

꼼꼼한 재은씨 기본편 (4) 본문

ios/책공부

꼼꼼한 재은씨 기본편 (4)

훈식이 2021. 10. 31. 05:36
728x90
Chat 4

화면 전환

iOS에서 화면을 전환하는 방법에는 크게 두 가지

소스 코드를 통해 전환하는 방식 (프로그래밍적(동적)으로 화면을 전환)
스토리보드가 제공하는 기능을 이용하여 전환하는 방식 (GUI 방식(정적)으로 화면을 전환)

방식은 분류 기준에 따라 크게 4가지로 나뉨.

뷰 컨트롤러의 뷰 위에 다른 뷰를 가져와 바꿔치기하기 (특수한 상황에서 제한적으로 사용)
뷰 컨트롤러에서 다른 뷰 컨트롤러를 호출하여 화면 전환하기
내비게이션 컨트롤러를 사용하여 화면 전환하기
화면 전환용 객체 세그웨이를 사용하여 화면 전환하기

1 -> 일부 부 뷰 컨트롤러들이 콘텐츠를 직접 배치하여 화면을 보여주는 역할 대신 다른 뷰 컨트롤러를 구조화하는 역할을 함.
이같은 뷰 컨트롤러를 '컨테이너 뷰 컨트롤러' 라고 함.
나머지 2,3,4 -> 뷰 컨트롤러를 호출하는 방식. 전환할 화면을 담당하는 뷰 컨트롤러의 인스턴스를 생성하고, 이를 불러들여서 기존의 화면위에 덮는것.
현재의 화면이 다른 화면으로 완전히 교체되는것이 아닌, 현재 화면이 있는 상태에서 그 위에 새로운 화면이 얹어지는 모양새.
--> 기존 화면과 새로운 화면 사이에는 서로 참조 관계가 성립.
특성 두가지.

  • 다음 화면으로 이동하는 방법과 이전 화면으로 되돌아가는 방법이 다름.
  • 화면 전환 방식에 따라 이전 화면으로 되돌아가는 방법이 다름.

다음 화면으로 이동하는 방법과 이전 화면으로 되돌아가는 방법이 다르므로 구분하여 적용해야 함.
화면 전환 방식에 따라 이전 화면으로 되돌아가는 방법도 달라짐.

화면 전환 기법1 : 뷰를 이용한 화면 전환

하나의 뷰 컨트롤러 안에 두 개의 루트 뷰를 준비한 다음, 상태에 따라 뷰를 적절히 교체해 주는 것.(필요에 따라 완전히 바꿔치기 혹은 덮어 가려지게 가능)
-> 하나의 뷰 컨트롤러가 두 개 이상의 루트 뷰를 관리해야 하므로 좋은 방법은 아님.
뷰를 이용하여 하나의 뷰 컨트롤러가 하나의 루트 뷰만 관리하게 할 수 있는 방식도 있지만, 단점 존재.
--> 될 수 있으면 뷰를 이용한 화면 전환은 지양.

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

현재의 뷰 컨트롤러에서 이동할 대상 뷰 컨트롤러를 직접 호출해서 화면을 표시하는 방식.(프레젠테이션 방식)
UIViewController클래서에서 정의된 메소드인 present(:animated:) , 프레젠트 메소드라고 부름.
Present(<새로운 뷰컨트롤러 인스턴스>, animated:<애니메이션 여부>)
첫번째 인자값 : 새로운 화면을 담당하는 뷰 컨트롤러의 인스턴스.
두번째 인자값 : false입력시 아무런 효과 없이 화면 바뀌고, true 입력시 화면 전환 시 애니메이션 효과가 적용됨.
Present(
:animated:completion:) -> 세번째 매개변수를 추가하여 화면 전환이 완료되는 시점에 맞추어 특정 로직 실행 가능
이처럼 하나의 처리가 끝나기를 기다리지 않고 다음 작업을 바로 이어서 수행하는 방식을 비동기 방식이라고 부름.
화면 전환할때 프레젠드 메소드를 이용했다면, 이전 화면으로 복귀할때는 dismiss(animated: ) 복귀 메소드를 사용
이 메소드에도 dismiss(animated: completion: ) 도 마찬가지로 가능.

      @IBAction func moveNext(_ sender: UIButton) {
        // 이동할 뷰 컨트롤러 객체를 StoryboardID 정보를 이용하여 참조.
        let uvc = self.storyboard!.instantiateViewController(withIdentifier: "SecondVC")
        // 화면 전환할 때의 애니메이션 타입
        uvc.modalTransitionStyle = UIModalTransitionStyle.coverVertical
        // 인자값으로 뷰 컨트롤러 인스턴스를 넣고 프레젠트 메소드 호출
        self.present(uvc, animated: true)
    }
}

UIStoryboard 초기화 과정에서 파일을 직접 지정 하는 경우

let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let uvc = storyboard.instantiateViewController(withIdentifier: "SecondVC")

전환 효과는 UImodalTransitionStyle 객체에 enum타입으로 정의되어 있으며 4개의 기본 전환 스타일이 제공됨.

coverVertical - 아래에서 위쪽으로 새로운 화면이 올라가면서 전환되는 효과. 전환효과 따로 미지정시 기본으로 적용됨.
crossDissolve - 디졸브 상황에서 두 화면이 서로 교차하면서 전 화면이 사라지고 다음 화면이 뚜렷하게 나타나는 전환 효과.
flipHorizontal - 화면 중앙 가상의 축을 기준으로 화면이 돌아가는 효과를 주면서 새로운 화면으로 전환
partialCurl - 화면의 오른쪽 아래 모서리에서 시작해 페이지가 말려 올라가는 효과를 주며 새로운 화면으로 전환

뒤로 가기 버튼 만들기

추가한 뷰 컨트롤러에서 버튼 생성 후 메소드를 추가하려면 소울메이트 찾아줘야 함.
(스토리보드의 뷰 컨트롤러와 컨트롤러 클래스가 연결되어야 함)
cmd + N 을 누른다음 Swift File을 생성.
UIViewController클래스를 상속받는 SecondViewController 클래스 생성.

import UIKit
class SecondViewController: UIViewController {

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

메인 스토리보드에서 추가한 뷰 컨트롤러 누른 후 인스펙터창에서 Identify Inspector -> Custom Class영역에서 Class항목을 열어 연결시켜줌.
애니메이션 효과를 true로 설정했으므로 화면 복귀시에 애니메이션 효과가 연출됨. 이때, 연출되는 애니메이션 효과는 화면 전환 시에 사용된 효과가 반대 흐름으로 적용됨.
화면을 복귀한답시고 self.present(_:animated)메소드를 사용하면, 이전 화면으로 되돌아가는 것이 아닌, 이전 화면을 지금 화면위에 다시 표시하는 꼴이므로 화면을 복귀할때는 dismiss(animated:)

  • 전활할 때 - present(:animated:) / present(:animated:completion:)
  • 복귀할 때 - dismiss(animated:) / dismiss(animated: completion:)
내비게이션 컨트롤러를 이용한 화면 전환

앱의 내비게이션을 표시해줄 수 있는 내비게이션 바 가 내장되어있음.
뷰 컨트롤러들의 전환을 직접 컨트롤하고, 앱의 내비게이션 정보를 표시하는 역할을 할 뿐만 아니라 화면 전환이 발생하는 뷰 컨트롤러들의 포인터를 스택으로 관리하여 원하는 화면에 접근하기 쉽게 함.
독립된 자신만의 화면을 가지지 않는 대신, 이 컨트롤러가 제어하는 모든 뷰 컨트롤러에 내비게이션 바를 생성하는 특징이 있습니다.
내비게이션 컨트롤러는 항상 콘텐츠 계층 구조의 시작점 역할을 하는 뷰 컨트롤러와 함께 다니는데, 이를 루트 뷰 컨트롤러라고 함.
루트 뷰 컨트롤러는 내비게이션 컨트롤러에 직접 연결된 컨트롤러이므로 화면 UI상단에 내비게이션 바가 표시됨.
내비게이션 컨트롤러는 화면에 현재 표시되고 있는 뷰 컨트롤러들을 내비게이션 스택을 이용하여 관리함. (배열 형식)

스토리보드에 내비게이션 컨트롤러 추가하는 방법 두가지

  • 오브젝트 라이브러리에서 내비게이션 컨트롤러 선택하여 추가 ( 루트 뷰 컨트롤러 역할을 하는 테이블 뷰 컨트롤러도 함께 추가됨)
  • Embed In 기능 이용 (낙하산 기능) - 스토리보드에서 선택된 뷰 컨트롤러를 루트 뷰 컨트롤러로 삼아 내비게이션 컨트롤러만 추가
import UIKit

class ViewController: UIViewController {

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

이때, 두번째 뷰 컨트롤러의 스토리보드에는 상단에 아무것도 없지만, 내비게이션 컨트롤러를 통해 이동하여 상단에 내비게이션 바가 추가됨.
내비게이션 컨트롤러가 추가된 상태에서 프레젠트 메소드를 추가하여 화면을 전환하면 내비게이션 바는 추가되지 않음.


세그웨이를 이용한 화면 전환

세그웨이(Segue)라고 불리는 객체는 스토리보드에서 뷰 컨트롤러 사이의 연결 관계 및 화면 전환을 관리하는 역할.
세그웨이는 화면과 화면을 연결하기 위해 아무런 소스 코드도 필요로 하지 않음.
뷰 컨트롤러와 뷰 컨트롤러 또는 화면 전환의 매개체가 되는 버튼과 뷰 컨트롤러 사이를 직접 연결하는 식으로 화면 전환 관계를 구성.
스토리보드상에서 뷰 컨트롤러 사이에 연결된 화살표로 표시.

세그웨이를 이용하면 뷰 컨트롤러에 대한 정보가 없어도 되고, 뷰 컨트롤러의 객체를 생성할 필요도 없음.
세그웨이가 실행되는 순간 스토리보드를 통하여 이미 세그웨이의 출발지와 목적지 뷰 컨트롤러에 대한 인스턴스가 생성되고, 그 포인터가 세그웨이 객체에 설정됨.

세그웨이의 목적지는 뷰 컨트롤러이지만, 출발점은 뷰 컨트롤러 자체가 될 수도(메뉴얼 세그웨이), 버튼 등일 경우도(액션 세그웨이 혹은 트리거 세그웨이)
두 방식은 실행하는 방식에서만 차이가 있고, 같음

액션 세그웨이(Action Segue) - 화면 전환을 위해 프로그래밍 코드가 일절 필요 X, 스토리 보드에 구현된 객체를 트리거로 지정하기만 하면 되므로 전체적 구성도 굉장히 단순해짐 + 프로그래밍 코드를 사용할때에 비해 비교도 안되게 빠른 시간 내에 화면 이동을 구현 가능.

show타입으로 설정 시 내비게이션 바가 생성되고 내비게이션 컨트롤러의 통제 하에 화면이 이동됨.
Present Modally타입 생성 시 프레젠드 메소드를 통하여 화면이동하는것과 같음.
내비게이션 컨트롤러 없이 show타입 생성 시 Present Modally방식으로 실행됨.

매뉴얼 세그웨이(Manual Segue) - 해당 이벤트만 발생하면 자동으로 실행되는 액션 세그웨이와 달리 뷰 컨트롤러와 뷰 컨트롤러 사이에 연결되는 수동 실행 세그웨이 -> 트리거 없이 수동으로 실행해야 하므로 소스 코드에서 세그웨이를 실행할 메소드를 호출해야함.

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

필요한 시점에서 세그웨이 식별자를 통해 특정 세그웨이를 지정하고 위 메소드를 호출하면, 세그웨이가 실행되면서 화면이 전환되는 구조

Unwind - 화면 복귀
반대방향으로 통하는 세그웨이 생성 -> 안됨.
화면 복귀용 메소드 사용 혹은 Unwind Segue 이용
Unwind Segue - 뷰 컨트롤러 상단의 도크 바 아이콘 중 세번째 Exit 이용

Unwind Segue를 이용하여 한꺼번에 여러 페이지 복귀하기.


커스텀 세그웨이

UIKit 프레임워크에서 제공하는 기본적인 기능의 세그웨이로는 원하는 기능을 충분히 구현하기 어려운 경우 UIStoryboardSegue클래스를 서브클래싱하여 새로운 기능을 갖춘 세그웨이 객체를 정의할 수 있도록 지원.

전처리 메소드

프로그래밍 코드를 통한 화면전환 - 구현하기 어렵고 상대적으로 난이도가 있지만 화면 전환 과정을 직접 제어할 수 있기 때문에 자유도가 높음
세그웨이를 이용한 화면전환 - 구현이 쉽고 간단하긴 하지만 화면 전환 과정에서 우리가 제어할 수 있는 자유도가 제한됨.
전처리 메소드(Pre-Process Method) - 화면을 전환하기 전에 필요한 처리를 해줌. -> 세그웨이를 이용하여 화면을 전환하는 과정에서 뭔가 특별한 처리가 필요할때 사용.

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

주의. 액티브 스킬이 아닌 패시브 스킬(비유). 메소드의 호출 주체는 우리가 아닌, 우리가 구현해놓으면 시스템이 호출하는 방식.

본 글은 꼼꼼한 재은씨의 스위프트 시리즈 책을 보고 정리한내용입니다.

728x90

'ios > 책공부' 카테고리의 다른 글

꼼꼼한 재은씨 기본편 (3)  (0) 2021.10.29
꼼꼼한 재은씨 기본편 (2)  (0) 2021.10.25
꼼꼼한재은씨 기본편 (1)  (0) 2021.10.21
Doit (2)  (0) 2021.06.08
Doit (1)  (0) 2021.06.08