1. Code Next: 코드로 화면 이동.
다음 화면이 코드로 작성되어 있을때만 가능한 방법
2. StoryBoard with Code
코드로 스토리보드 객체를 생성해서, 화면 이동 버튼
3. StoryBoard with Segue
스토리보드에서의 화면 이동(간접 세그웨이) 버튼
4. Storyboard with Button
스토리보드에서 버튼의 직접 세그웨이
1. Code Next : 코드로 작성한 컨트롤러로 코드를 통해 이동
다음 넘어갈 화면을 스토리보드가 아닌 코드로 작성해놓았다. 다음 화면은 FirstViewController.swift이다.
let firstVC = FirstViewController() //코드로 작성한 FirstViewController를 메모리에 올림
firstVC.someString = "clamp" // 데이터를 전달해줄 수 있다.
firstVC.modalPresentationStyle = .fullScreen // firstVC의 presentationStyle을 설정
self.present(firstVC, animated: true, completion: nil) // 생성한 FirstViewController를 present로 띄움.
present메서드는 MainViewController로 상속받은 UIViewController에 구현되어있다
데이터를 전달하기 위해 FirstViewController내부에 someString이라는 String? 변수를 선언해두었다. 이를 활용해 다음 화면으로 넘어갈 때 데이터를 전달할 수 있다.
FistViewController에서 mainLabel.text = someString 으로 라벨에 텍스트가 전달된다.
그렇다면? firstVC.mainLabel.text = "clamp" 이런식의 작성을 하지 않는 이유
이런 방식을 사용하지 않는 이유는 스토리보드 방식으로 생성했을 때에는 아예 전달이 불가능하며 에러가 발생한다.
왜냐하면 코드로 화면을 만드는 경우엔 모든 저장속성이 메모리에 한꺼번에 올라간다.
그런데, 스토리보드로 만들면
1. 코드로된 뷰컨트롤러를 메모리에 올리고
2. 스토리보드를 메모리에 올린다. 그 다음
3. 코드와 스토리보드를 연결하는 과정을 거치기 때문에 메모리에 생성되기 전에 접근을 하게된다.
present된 화면을 다시 내리고 전 화면으로 돌아가는 방법
self.dismiss(animated: true)
2. StoryBoard with Code: 코드와 스토리보드로 작성한 컨트롤러로 코드로 이동
스토리보드와 코드로 다음으로 넘어갈 SecondViewController를 생성했다.
스토리보드로 생성해서 SecondViewController클래스와 이어준 뷰 컨트롤러는 인스턴스를 그냥 생성하면 스토리보드와 연결되지 않아서
❌아래의 코드 방식으로 생성이 불가능하다.
let secondVC = SecondViewController() // 이 방식은 스토리보드와 연결되지 않는다
메모리에 SecondViewController라는 인스턴스가 존재하지만 우리가 UI를 스토리보드로 만들면 스토리보드로 만든 UI들이 힙 영역에 따로 존재한다. 그래서 스토리보드로 UI를 짤 때에는 코드인스턴스와 스토리보드 인스턴스가 따로존재하며, 나중에 이 인스턴스들을 하나씩 연결해줘야 한다.(이를 연결하는게 IBOutlet같은것들)
메모리에 따로 존재하는 인스턴스들을 연결해주는 과정을 내부메커니즘으로 거치게 되므로 위와같은 단순히 인스턴스를 찍어내는 방식으로는 스토리보드와 연결되지 않는다.
우리가 만드는 ViewController는 UIViewController라는 클래스를 상속받는다.
UIViewController를 상속받았기 때문에 storyboard라는 UIStoryboard를 상속받았고. 이미 존재한다.
여기에 instantiageViewController(withIdentifier: String)라는 메서드가 존재한다
⭕️ withIdentifier라는 식별자를 가지고 스토리보드로 만든 뷰컨트롤러를 생성할 수 있다.
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
present(secondVC, animated: true, completion: nil)
instantiageViewController(withIdentifier: String)의 리턴타입은 UIViewController가 되며 이를 또 다시 타입캐스팅을 해야한다. 이를 다시 SecondViewController타입으로 다운캐스팅 해줘야한다. 구체적이지 않은 UIViewController타입을 실제로 생성된 인스턴스는 훨씬 더 구체적인 타입인 SecondViewController타입으로 만들어줘야한다.
이를 present해주면 된다.
옵셔널 바인딩을 활용한 코드들
// if let 바인딩
if let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondVIewController") as? SecondViewController{
present(secondVC, animated: true)
}
// guard let 바인딩
guard let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondVIewController") as? SecondViewController else { return }
present(secondVC, animated: true)
데이터 전달방식은 1번과 같다.
UI를 코드로작성할 때와 스토리보드로 작성할 때의 차이⭐️⭐️⭐️
코드만으로 작성한 뷰컨트롤러는 메모리에 한번에 올라간다.
스토리보드와 코드로 작성한 뷰컨트롤러는 메모리에 코드로작성한 인스턴스, 스토리보드로 작성한 인스턴스가 따로 올라간다.
이 후 두 인스턴스를 연결해주는 작업을 거치게되는데 이 작업이 일어나는 순간이 viewDidLoad이다.
두 인스턴스가 모두 메모리에 Load되고, 호출되는 순간이다. viewDidLoad가 호출되기 전엔 라벨이나 UI요소들은 스토리보드로 작성이 되었으므로 인스턴스를 찍어내고 접근하는 방식으론 label.text등등을 설정할 수 없다.
그러므로 ViewDIdLoad에 label.text를 설정해주는 방식의 코드는 가능하지만, let vc = SecondViewController() 방식으로 찍어낸 후 vc.label.text 엔 접근할 수 없다
3. StoryBoard with Segue: 스토리보드에서의 화면 이동(간접 세그웨이)
스토리보드에서 ViewController에서 control + 위 버튼을 클릭해 이동하고싶은 뷰컨트롤러를 드래그앤 드랍하면 세그웨이(Segue)를 생성할 수 있다. 생성할 때 present방식을 결정할 수 있고 속성인스펙터에서 identifier를 설정할 수 있는데 여기선 toThirdVC로 한다.
여기서 세그웨이는 파란색 화살표이며, 이는 화면 이동을 관리하는 객체이다.
이를 StoryBoard With Segue버튼이 눌렸을 때 작동시킬것이며, 화면 이동은 아까 생성한 세그웨이가 담당한다.
버튼이 눌렸을 때 세그웨이를 활성화 시켜줘야하고, 활성화시켜주는 메서드는 이것이다.
withIdentifier: 세그웨이의 식별자
sender: 보내는 녀석을 적는 란인데 nil을 적어도 상관없고 일반적으로 self(보내는 뷰컨트롤러)를 작성한다.
이 performSegue는 이미 UIViewController클래스에 정의되어있다.
그리고 이 performSegue를 실행하면 스토리보드에 생성된 세그웨이가 동작하게 되는것이다. 그러면서 다음 화면으로 이동하게 되는것이다.
세그웨이 방식에서의 데이터 전달은 위와 다르다.
다른 방식은 직접 인스턴스를 찍어내는 방식으로 진행했지만. 이 방식에선 어떤 메서드를 재정의해줘야한다.
이 메서드로 데이터를 전달할 수 있다. 왜냐하면 이 메서드의 파라미터가 UIStoryboardSegue이기 때문이다.
UIStoryboardSegue를 통해서 다음 화면으로 넘어가는 뷰 컨트롤러에 접근할 수 있고, 데이터를 전달할 수 있다.
// 3) 스토리보드에서의 화면 이동(간접 세그웨이)
@IBAction func storyboardWithSegueButtonTapped(_ sender: UIButton) {
performSegue(withIdentifier: "toThirdVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// 1. identifire확인
if segue.identifier == "toThirdVC"{
// 2. 구체적인 타입으로 타입캐스팅
let thirdVC = segue.destination as! ThirdViewController
// 3. 이제 ThridViewController에 접근 가능
thirdVC.someString = "clamp"
}
}
여기서 세그웨이는 파란색 화살표이며, 이는 화면 이동을 관리하는 객체이다. performSegue를 실행함으로서 화면이동을 관리하는 객체인 세그웨이를 활성화시키고, performSegue내부에서 prepare(for segue:, sender)를 호출한다.
4. Storyboard with Button: 스토리보드에서 버튼의 직접 세그웨이
버튼을 직접 선택하고 컨트롤을 누르고 이동할 뷰컨트롤러로 드래그하면 직접세그웨이가 생성된다.
이 전과 달리 버튼에서 직접 다른 뷰컨트롤러(FourthViewController)를 연결했다.
이렇게 생성한 세그웨이는 3번 방법과 달리 버튼과 세그웨이가 직접적으로 연결되어있고, 버튼을 누르는 즉시 performSegue가 작동한다.
어쨋든 이 방식 또 한 데이터를 전달하기 위해 prepare함수를 구현해야 한다.
데이터 전달 방식은 3. 간접세그웨이 방식과 동일하다.
하지만 조건에 따라서 performSegue가 작동할지 안할지 구현할 수 있다.
이는 shouldPerformSegue(withIdentifier:, sender:) -> Bool 메서드를 재정의함으로 구현할 수 있다. 그리고 이 shouldPerformSegue는 직접 세그웨이를 만들었을 때에만 실행된다.(버튼에서 직접적으로 연결했을 때)