안녕하세요! 벌써 4번째 TIL이네요.
요즘 시간이 너무 빨리가서 무서워요.
원래 계획대로라면 MVVM으로 간단한 프로젝트를 만들어보고
바인딩을 공부하면서 새로 이전 프로젝트를 MVVM 패턴으로 바꿀 예정이었는데요.
예상치 못한 오류에 시간을 많이 소모해서 못했습니다.
알고나니 정말 별 거 없는 오류였습니다.
일단 오늘 학습한 내용은 크게
- ViewModel에서 화면을 전환하는 로직
- 스토리 보드 지우는 법
- 'required' initializer 'init(coder:)' 오류에 관하여 입니다.
ViewModel에서 화면 전환하기
이전에 MVVM 패턴에서는 ViewModel에서 로직을 담당한다고 하였습니다.
그래서 View에서 최대한 로직을 빼는데
화면을 전환하는 것도 하나의 로직으로 보고 ViewModel에서 처리한다고도 하였습니다.
간단하지만 코드 예시로 ViewModel에서 화면을 전환하는 법을 소개합니다.
(사실 ViewController에서 화면을 전환하던 방법과 큰 차이는 없습니다.)
예시 코드는 CalculateButton을 누르면 ResultViewController로 화면이 이동하는 코드입니다.
1. addTarget 연결하기
기존 방식과 마찬가지로 생성된 버튼에 .addTarget으로 함수를 연결해줍시다.
func setAddTarget() {
calculateButton.addTarget(self, action: #selector(calculateButtonTapped), for: .touchUpInside)
}
2. 연결된 함수에서 ViewModel의 함수 동작시키기
#selector(셀렉터)는 objective-c 방식을 지원하기 때문에 연결할 함수를 @objc로 선언하는거 아시죠?
연결된 함수에서 실행시킬 함수는 ViewModel에 위치한 함수 입니다.
기준이 되는 뷰 컨트롤러를 전달하기 위해 파라미터로 self를 전달합니다.
@objc func calculateButtonTapped() {
// 뷰 모델의 로직 실행
viewModel.calculateButtonTapped(fromCurrentVC: self, animated: true)
}
3. ViewModel에서 화면 전환 로직 실행
func calculateButtonTapped(fromCurrentVC: UIViewController, animated: Bool) {
// 현재 창
let navVC = fromCurrentVC.navigationController
// 이동할 창
let resultVC = ResultViewController()
// 전체화면으로 설정
resultVC.modalPresentationStyle = .fullScreen
// resultVC로 이동
navVC?.pushViewController(resultVC, animated: animated)
}
NavigationController를 사용하지 않는 경우
바로 넘기면 됩니다.
func calculateButtonTapped(fromCurrentVC: UIViewController, animated: Bool) {
// 이동할 창
let resultVC = ResultViewController()
// 전체화면으로 설정
resultVC.modalPresentationStyle = .fullScreen
// 화면 이동
fromCurrentVC.present(resultVC, animated: animated, completion: nil)
}
Swift에서 스토리 보드 지우는 법
코드 베이스로 프로젝트를 진행할 때 가끔 스토리 보드와 관련된 설정이 충돌해서 오류가 발생할 수 있습니다.
저도 몰랐는데 이번에 강제로 알게 되었습니다.
(구체적으로 스토리보드의 생성자가 내부적으로 남아 있어서
SceneDelegate에서 설정한 NavigationController에서 인스턴스를 호출할 때 제대로 동작하지 않은 것 같습니다.)
MVVM 패턴을 적용하면서 View에서 ViewModel을 사용하게 되면서 자연스럽게 생성자를 만들게 되었는데,
계속 오류가 나는 겁니다.
처음에는 생성자와 관련된 이해가 부족한가 하고 개념을 복습해도 무엇이 문제인지 못찾겠더라구요.
오늘 하루종일 무엇이 문제인가 고민하다가 스토리 보드가 남아있어서 생길 수 있는 충돌이라고 듣고
바로 스토리보드를 지워보니까 3분만에 해결이 되었습니다.
1. main 파일 삭제하기
우클릭 -> Delete -> Move to Trash
2. TARGETS에서 UIKit Main Storyboard File Base Name 삭제하기
왼쪽 상단에 프로젝트 이름으로 된 파일 클릭 -> 화면에 TARGETS 클릭 -> 중앙 상단에 Build Settings 클릭 -> main 검색 -> UIKit Main Storyboard File Base Name 삭제
Main Storyboard File Base Name 클릭하시고 delete 키나 뒤로가기 키 누르시면 됩니다.
3. Info에서 Storyboard Name -> main 삭제하기
Info -> Application Scene Manifest -> Scene Configuration -> Window Application Session Role -> Item 0 -> Storyboard Name
Storyboard Name 클릭하시고 delete 키나 뒤로가기 키 누르시면 됩니다.
4. 코드로 화면 설정하기 (rootViewController)
이제 코드로 첫 화면을 지정해주어야 합니다.
왼쪽 상단에 SceneDelegate로 가셔서 해당 코드를 찾아 수정해줍시다.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
'required' initializer 'init(coder:)' 오류에 관하여
추가로 이번에 여러가지 찾다가 알게 된 사실인데,
생성자를 추가하면 옆에 뜨는 오류 메시지 다들 아실텐데요.
'required' initializer 'init(coder:)' must be provided by subclass of 'UIViewController'
오류 메세지를 클릭해서 뭔가 추가하면 자동으로 이런 코드를 만들어줍니다.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Additional initialization code
}
이렇게 추가하면 오류가 사라져서 그냥 그런갑다 하고 넘어갔었는데,
이게 기본으로 설정된 뷰 컨트롤러의
required init (필수 생성자)였습니다.
필수 생성자는 상위 클래스에서 정의하면 하위에서 반드시 구현해야 하는 특징이 있죠.
그래서 원래는 구현해야 하는 생성자인데 모든 프로퍼티가 기본 값을 가지고 있어서
따로 생성자를 작성하지 않는 경우에는 이 required init (필수 생성자)를 구현하지 않아도 된다고 합니다.
그래서 결과적으로 required init (필수 생성자)는 지정 생성자를 직접 구현할 경우에만 필수라고 합니다.
참고:
https://babbab2.tistory.com/171
Swift) 초기화(Initializers) 이해하기 (5/6) - Required initializer
안녕하세요, 소들입니다 :> 유연 근무제로 인해 공부 시간과 취미 시간을 모두 얻었지만 피곤을 x100배로 얻어버렸다ㅠ;; 망할 그래도 전 요즘 기타 치느라 박인 왼손의 굳은살을 자랑하는 낙으로
babbab2.tistory.com
https://storing.tistory.com/43
[Swift / Xcode] 프로젝트 Storyboard 삭제 세팅 - Code Base UI
프로젝트 진행 간 Storyboard를 제거하고 Code로만 UI를 구성해보게 되었는데, 이를 위해 필요한 세팅을 기록해두고자 합니다. ✅ 1. Main Storyboard 삭제 프로젝트에서 Storyboard를 제거하는 것이 목표이
storing.tistory.com