다이어리 앱을 개발하면서 평소 토이프로젝트르 할 때는 크게 고려하지 않아도 됐던 화면전환 방식을 사용자의 편의를 중점으로 생각하며 개발하다 보니 편리함을 위해 present방식으로 화면을 띄우던 방식을 push 방식을 사용해야 하는 상황이 생겼다.
present와 push 방식은 결과물만 보자면 크게 차이는 없지만 내가 직접 코드를 작성하며 느낀 차이점에서는
1. 왼쪽으로 스와이프하여 뷰를 제거하는 방식
2. 새로운 뷰가 나타날 때 애니메이션 방식 (가로 방향으로 뷰가 나타나게 하고 싶으면 push로 해야만 하는 것 같다.)
더 있었던 것 같은데 크게는 이정도..? 이게 그렇게 큰 차이인가 하는데 사소한 방식에서 뭔가 앱이 허술해보이는..? 느낌이 드는 것 같았다.
처음에는 내가 편하다고 생각하는 방식인 present로 뷰를 띄웠는데 코드를 짜다보니 push로 띄워야만 하는 상황이 생겼다. 나는 앱을 사용할 때 스와이프로 뷰를 제거하는데 이 방식은 present로는 사용이 불가한 것 같았다.
그리고 앱이 최초실행이냐 아니냐에 따라 생략해도 되는 뷰가 있었기 때문에 조건에 따라 다르게 뷰를 띄워주어야 했는데, 메인에서 기존에 쌓아뒀던 뷰를 모두 제거하여 루트뷰를 다시 지정해주어야 했다.
문제는 인터넷에 있는 코드, 전에 받아서 참고하던 코드에서도 올바르게 작성했는데 화면전환이 동작하지 않았다.
시행착오 끝에 알아낸 방식은 스토리보드 구성의 문제였다.
먼저 루트뷰로 지정하는 방법이다.
1. 첫 번째 방법
extension UIWindow {
func replaceRootViewController(_ replacementController: UIViewController, animated: Bool, completion: (() -> Void)?) {
let snapshotImageView = UIImageView(image: self.snapshot())
self.addSubview(snapshotImageView)
let dismissCompletion = { () -> Void in // dismiss all modal view controllers
self.rootViewController = replacementController
self.bringSubviewToFront(snapshotImageView)
if animated {
UIView.animate(withDuration: 0.4, animations: { () -> Void in
snapshotImageView.alpha = 0
}, completion: { (success) -> Void in
snapshotImageView.removeFromSuperview()
completion?()
})
}
else {
snapshotImageView.removeFromSuperview()
completion?()
}
}
if self.rootViewController!.presentedViewController != nil {
self.rootViewController!.dismiss(animated: false, completion: dismissCompletion)
}
else {
dismissCompletion()
}
}
func snapshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
drawHierarchy(in: bounds, afterScreenUpdates: true)
guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return UIImage.init() }
UIGraphicsEndImageContext()
return result
}
}
let vc = self.storyboard?.instantiateViewController(withIdentifier: "MainVC")
UIApplication.shared.keyWindow?.replaceRootViewController(vc!, animated: true, completion: nil)
2. 두 번째 방법
let vc = self.storyboard?.instantiateViewController(withIdentifier: "main")
UIApplication.shared.windows.first?.rootViewController = vc
UIApplication.shared.windows.first?.makeKeyAndVisible()
그리고 스토리보드는 다음과 같이 구성하였다.
나는 두번째 코드로 해결하였는데, 여기서 실수한 점이 withIdentifier에 네비게이션 컨트롤러의 아이디를 지정하고 작성해주어야 한다.
그리고 루트뷰로 지정하고 싶은 부분에 네비게이션 컨트롤러를 root로 연결해주어야 한다.
생각해보면 크게 어려운 문제는 아니였는데 너무 present방식으로만 짜다보니까 navigation방식이 낯설어서 많이 헤맨것 같다. 앞으로는 두 방식 모두 사용하도록 해야게따ㅎㅎ
'iOS > Swift' 카테고리의 다른 글
[iOS] 타입 주석(Type Annotation)과 타입 추론(Type Inference) (0) | 2022.12.27 |
---|---|
[iOS/Swift] CoreData 공부하기 (0) | 2022.08.23 |
Reactive X 공부 (0) | 2022.07.19 |
[iOS/Swift] TableView 만들기 (0) | 2022.03.21 |
[iOS/Swift] 화면에서 키보드가 사라지게 하는 방법 (0) | 2022.02.10 |