안녕하세요, iOS 개발하는 루피입니다!
오늘은 제가 개인적으로 진행하고 있는 토이 프로젝트에 관해 글을 써보려고 합니다. 바로.... 오렌지 마켓인데요 ㅋㅋㅋㅋ.
맞습니다. 당근마켓 클론 코딩이라고 생각하시면 됩니다. 제가 최근에 필요 없는 물건을 정리하면서 당근 마켓을 애용하고 있는데, 앱을 따라 만들어 보면 재미있을 거 같아 공부할 겸 만들어보고 있습니다.
매번 클론 코딩을 하게 되면, 강의를 보고 따라치는 형식이 많았는데 이번에는 코드를 따라 치는 것이 아닌 앱을 보고 코드를 만들어 보는 형식으로 만들어 보고 있습니다. 확실히 이렇게 앱을 만들어 보니, 배우는 것도 많고 앱의 규모가 크다는 것을 몸 소 체험 하고 있습니다. 어떻게 폴더링 하고 어떻게 코드를 분리할 것인지에 대해 고민하는 저의 모습을 보게 되더라고요....ㅎ
자 그러면 다른 얘기는 각설하고, 본론으로 들어가 보도록 하겠습니다.
이번에 프로젝트를 진행하며,구현한 내비게이션 이동시 스플래시 화면에 대해 정리해 보겠습니다. 우선 먼저 당근 마켓 앱부터 보시죠.
보이는 거처럼 당큰 마켓 애플리케이션은 하단에 TabBar를 이용한 내비게이션 방식과 버튼을 통한 기본 내비게이션 방식을 혼합한 형식으로 화면 전환하는 것을 확인할 수 있습니다. 또한 상단의 버튼을 터치하면, 화면이 전환되면서, 일정 시간 동안 Splash 화면이 노출되고 이후에 이동한 View가 노출되는 것을 확인할 수 있습니다.
이러한 과정에서 마주한 트러블 슈팅과 이를 해결한 과정을 정리 해보겠습니다.
1. 홈 화면에서만 존재해야 하는 TabBar가 다음 뷰에서도 노출되는 트러블
음... 우선 결론부터 말씀드리면 아주 간단히 해결했습니다.
@objc private func buttonTapped(sender: UIButton) {
switch sender.tag {
case 1:
let newVC = AlbaViewController()
newVC.hidesBottomBarWhenPushed = true // TabBar 감추기
navigationController?.pushViewController(newVC, animated: true)
}
}
보이는 거와 같이 자체 컴포넌트가 존재하더라고요.... 일단 해결했다면 오케이입니다. 컴포넌트와 메서드에 대해 좀 더 공부를 해봐야겠습니다 ㅎㅎ. 당근 마켓 경우 커스텀 TabBar를 사용하는 거 같은데 나중에 한번 구현해 봐야 할거 같습니다!
2. Splash 화면 구현
화면을 전환할 때 처음에는 뷰가 전환될 때 VC가 전환되자마자 Splash 화면을 SubView에 추가하여 최상위 계층에 추가하여 노출시키고 일정 시간이 지나면 SubView를 제거하는 방법을 구현하려고 했습니다.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupSplashView()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.removeSplashView()
}
}
그랬는데 스플래시 화면이 정상적으로 작동되지 않고 바로 다음 화면으로 넘어가더라고요... 그래서 고민하던 중
override func viewDidLoad() {
super.viewDidLoad()
self.view = splashView
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.view = albaView
}
}
이런 식으로 처음에는 ViewDidLoad에서 View를 SplashView로 지정한 이후에 일정 시간이 지난 후에 뷰를 다시 바꿔주는 방식을 선택했습니다. 그러자... 결과는... 원했던 방식으로 작동되더라고요 ㅎㅎ
하지만,
이런 방식으로 뷰를 직접 만지는 형태를 앱의 성능을 떨어뜨리는 방식이라는 피드백을 받고 다시 한번 첫 번째 시도했던 방식에서 조금 더 고민의 시간을 가졌습니다. 그 결과 제가 addsubView를 SplashView에서 SuperView위에 올리지 않고 있었더라고요..ㅎㅎ. addsubView를 수정하니 정상 작동되었습니다.
코드
import UIKit
class AlbaViewController: UIViewController {
var albaView = AlbaView()
override func viewDidLoad() {
super.viewDidLoad()
self.view = albaView
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.removeSplashView()
}
}
override func viewDidAppear (_ animated: Bool) {
super.viewDidAppear (false)
tabBarController?.tabBar.isHidden = true
}
private func removeSplashView() {
UIView.animate(withDuration: 0.3, animations: {
self.albaView.splashView.alpha = 0.0
}) { _ in
self.albaView.splashView.removeFromSuperview()
}
}
}
import UIKit
class AlbaSplashView: UIView {
lazy var splashLabel: UILabel = {
var label = UILabel()
label.text = "로딩 중..."
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 24)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setViewHierarchy()
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setViewHierarchy() {
self.addSubview(splashLabel)
}
private func setConstraints() {
splashLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
splashLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor),
splashLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor)
])
}
}
import Foundation
import UIKit
class AlbaView: UIView {
lazy var splashView: AlbaSplashView = {
var view = AlbaSplashView()
view.backgroundColor = .systemBlue
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setViewHierarchy()
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setViewHierarchy() {
self.addSubview(splashView)
}
func setConstraints() {
splashView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
splashView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
splashView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
splashView.topAnchor.constraint(equalTo: self.topAnchor),
splashView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
}
이처럼 클론 코딩을 하면서 겪은 트러블 슈팅을 해결한 내용을 정리해 보았습니다. 기록하지 않고 있다. 어느 정도 마무리 되고 나서 기억을 상기시켜서 기록하다 보니 코드나 문제 사항을 상세하게 적지 못했는데요. 문제사항을 마주할 때마다 겪은 문제를 정리해 나가는 습관을 들여야 될 거 같아요. 이상으로 글을 마무리하도록 하겠습니다. 언제든지 피드백은 환영입니다!
'트러블 슈팅' 카테고리의 다른 글
| [트러블 슈팅] ImageCache 에서 KingFisher 도입 (2) | 2025.06.12 |
|---|---|
| [트리블 슈팅] API 호출 대신 이미지 캐싱으로 성능 최적화하기 (0) | 2025.05.29 |
| [트러블 슈팅] SplashView로 UX 개선하기 (0) | 2025.05.29 |
| [트러블 슈팅] SwiftUI에서 느린 사진 업로드 문제 해결 (0) | 2025.04.27 |