이번에는 9강에 배운 뷰 컨트롤러 라이프 사이클(생명주기)과 스크롤뷰에 대해 정리해봤습니다.
ViewController의 생명주기
생명주기를 배워야 하는 이유는 뷰컨트롤러가 생성되면서 호출되는 메서드들 사이에 사용자가 직접 개입하고 싶은 상황이 생기기 때문입니다. 아래와 같이 주기를 갖기 때문에 "Life cycle(생명주기)"라고 합니다. 아래 이미지 외에 추가로 loadView, viewDidLoad 등 다른 메서드도 존재합니다. loadView는 뷰를 만들고 메모리에 올리는 역할을 하고, viewDidLoad는 UIViewController가 메모리에 로드 된 후 수행할 동작을 작성하게 됩니다. 이처럼 iOS에서 뷰컨트롤러의 생명주기에서 작동하는 메서드들을 오버라이드해서 사용자가 원하는 기능들을 구현하기 위해 생명주기를 알아야 합니다.
viewDidLoad
viewDidLoad는 UIViewController가 메모리에 로드 된 후 어떤 동작을 할지를 정의하는 메서드입니다. 이 메서드는 뷰가 메모리에서 해제되기 전까지 한번만 실행됩니다.(생명주기에서 한번만 실행됨) 이 메서드는 viewDidLoad를 오버라이드 할 때 bounds가 아직 설정되기 전이기 때문에 화면 크기에 대한 요소를 정의하는 것은 좋지 않다고 합니다.
Do not do geometry-related setup here! Your bounds are not yet set!
override func viewDidLoad() {
super.viewDidLoad()
}
viewWillAppear
viewWillAppear은 viewDidLoad와 다르게 생명주기에서 여러번 호출될 수 있습니다. 이 메서드를 오버라이드해서 사용하는 이유는 뷰컨트롤러가 메모리에 있으면서 언제든지 사라졌다 다시 돌아올 수 있기 때문입니다. 모델이나 데이터들을 뷰컨트롤러에 그려주는 작업을 하기도 합니다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
viewDidAppear
viewDidAppear에서는 네트워크 fetching, 타이머, 애니메이션이나 어떤 것을 observing 하기 시작하는 작업을 수행하기 좋습니다. 비용이 비싼 작업들을 수행하기 좋다고 하는데 이유가 뭘까요? 위 두 메서드에서는 뷰가 완전히 그려지지 않았지만 viewDidAppear가 호출 될 때는 뷰가 완전히 그려지고, 그 화면을 쓴다는게 확실하기 때문에 비용이 상대적으로 더 큰 작업들을 하기 괜찮다고 합니다.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
viewWillDisappear
UIViewController가 사라질 때 호출되는 메서드입니다. viewDidAppear나 다른 생명주기에서 로딩하거나, 타이머 같은 것들을 중지시키기 좋은 메서드라고 소개했습니다. 그렇게 중지시킨 동작들은 뷰가 다시 나타날 때 viewDidAppear와 함께 실행되게 하는 것이 좋은 방법이라고 소개됐습니다.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
viewDidDisappear
MVC가 화면에서 사라진 후에 호출되는 메서드입니다. 여러 상태를 저장하기에 좋은 메서드라고 합니다.
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
}
Geometry
viewDidLoad를 설명할 때 화면 크기와 관련된 작업을 안 하는 것이 좋다고 했습니다.
그러면 뷰의 크기에 대한 작업은 어디서 해야할까요 🤔 🤔
viewWillLayoutSubviews(), viewDidLayoutSubviews()를 사용하면 됩니다. 하지만 보통은 Autolayout을 사용하기 때문에 필요없다고 합니다. 이 메서드들을 오버라이드 할 때 서브 뷰에 바뀐 점이 없는데도 이 메서드가 호출될 수도 있기 때문에 주의해야 합니다. 예를 들어...
- viewWillLayoutSubviews 👉 뷰 컨트롤러가 뷰의 하위 뷰를 배치하려고 함을 알리기 위해 호출됩니다.
(뷰의 bounds가 결정되는 시점) - viewDidLayoutSubviews 👉 뷰가 방금 하위 뷰를 배치했음을 뷰 컨트롤러에 알리기 위해 호출됩니다.
override func viewWillLayoutSubviews()
override func viewDidLayoutSubviews()
Autorotation
화면을 회전할 경우 viewDidLayoutSubviews가 호출되게 됩니다. 이 때 아이폰 기본 계산기처럼 뷰가 다른 뷰로 바뀔 수도 있는데 이 때 아래 메서드를 활용하게 됩니다. 강의에서는 90% 확률로 학생들이 사용하지 않을거라고 합니다.
override func viewWillTransition(
to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator
)
Low Memory
음성이나 영상 같은 것들이 많은 용량을 차지할 때 아래 메서드가 뷰컨트롤러에 전달됩니다. 앱 메모리 누수가 심해서 앱 용량이 커질 경우 이 단계로 가게 된다고 합니다. 메모리 누수가 너무 심하면 앱이 강제종료 당할 수도 있습니다.
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// stop pointing to any large-memory things (i.e. let them go from my heap)
// that I am not currently using (e.g. displaying on screen or processing somehow)
// and that I can recreate as needed (by refetching from network, for example)
}
AwakeFromNib()
이것은 뷰컨트롤러의 생명주기가 아니지만 수업에서는 스토리보드에서 나온 모든 객체가 awakeFromNib으로 호출되기 때문에 언급했다고 합니다. 이 메서드는 클래스 초기화 다음, 세그웨이 준비 전 아울렛 연결 전에 호출됩니다.
override func awakeFromNib() {
super.awakeFromNib()
// can initialize stuff here, but it’s VERY early
// it happens way before outlets are set and before you’re prepared as part of a segue
}
ScrollView
스크롤뷰는 기기 화면보다 큰 사이즈의 뷰를 보여주기 위해 사용하는 뷰입니다. 예를들면 UITableView나 UICollectionView 등 많은 정보들을 갖고 있는 뷰를 감싸는 형식으로 쓰입니다. 9강에서는 스크롤뷰를 어떻게 사용해야하는지 간략하게 함수들을 통해 설명합니다.
UIScrollView에 서브뷰를 추가하기
UIScrollView를 사용할 때는 항상 contentSize를 정해줬어야 한다고 합니다. 하지만 AutoLayout이 등장한 이후로는 지정하지 않아도 된다고 합니다.
scrollView.contentSize = CGSize(width: 3000, height: 2000)
logo.frame = CGRect(x: 2700, y: 50, width: 120, height: 180)
scrollView.addSubview(logo)
aerial.frame = CGRect(x: 150, y: 200, width: 2500, height: 1600)
scrollView.addSubview(aerial)
스크롤 뷰의 현재 위치
스크롤 뷰의 contentOffset을 사용해서 스크롤 뷰에서 보이는 부분의 좌측 상단 좌표를 알 수 있습니다. 좌표 뿐 아니라 convert를 이용해서 현재 보고 있는 구역의 CGRect 값도 알 수 있습니다. 여기서 scrollView.bounds는 scrollView의 좌표 시스템 안에 있다고 합니다.
let upperLeftOfVisible: CGPoint = scrollView.contentOffset
let visibleRect: CGRect = aerial.convert(scrollView.bounds, from: scrollView)
코드로 스크롤 뷰 제어하기
scrollRectToVisible 메서드로 스크롤 뷰 내에 원하는 위치로 스크롤 시킬 수 있습니다.
func scrollRectToVisible(CGRect, animated: Bool)
스크롤 말고도 zooming 기능을 사용할 수 있습니다. 최대 최소 zoom scale을 지정해줄 수도 있고, 코드로 직접 확대할 수도 있습니다. delgate 메서드를 활용하면 zoom이 끝난 것을 알 수 있습니다.
// 확대 최대 최소 스케일 정하기
scrollView.minimumZoomScale = 0.5 // 0.5 means half its normal size
scrollView.maximumZoomScale = 2.0 // 2.0 means twice its normal size
// 코드로 확대하기
var zoomScale: CGFloat
func setZoomScale(CGFloat, animated: Bool)
func zoom(to rect: CGRect, animated: Bool)
// Zoom 끝났을 때 실행되는 메서드 (delegate)
func scrollViewDidEndZooming(UIScrollView,
with view: UIView, // from delegate method above
atScale: CGFloat)
참고자료
'CS193P' 카테고리의 다른 글
[iOS] 스탠포드 CS193P 11강 (0) | 2021.09.15 |
---|---|
[iOS] 스탠포드 CS193P 10강 (0) | 2021.09.14 |
[iOS] 스탠포드 CS193P 8강 (0) | 2021.09.02 |
[iOS] 스탠포드 CS193P 7강 (0) | 2021.09.01 |
[iOS] 스탠포드 CS193P 6강 (0) | 2021.08.31 |