말 그대로 view를 컨트롤 할수 있는 객체이다.
ViewController를 통해서
뷰의 내용업데이트 (ex. 상황에 때라 레이블 변경)
상호작용에 응답 (버튼을 누르면 어떤 동작을 줄것인지?)
등 뷰를 컨트롤 할수있다.
각 화면은 각 하나의 ViewController을 가지고 있어야 한다!!
만약 앱에서 다음화면으로 넘어갔다가 다시 전 전화면으로 돌아갔을때
전화면에 대한 데이터들은 어떻게 저장할것인가?
어떤 시점에 저장할것인가?
우리는 이 문제를 ViewControllerr가 가지고 있는 여러시점을 조작하여 해결할수 있다!
이렇게 여러단계가 존재한다.
그중 가장 익숙한건 viewDidLoad() 이다.
Xcode프로젝트를 생성하면 무조건 자동으로 생성되어있는 함수다.
이 함수는 앱의 화면에 들어서면 가장 먼저실행시키는 함수다.
이 함수는 예를 들어 스토리보드와 코드로 동작을 연결 시켰을때
스토리보드의 뷰들과 코드의 연결이 완료된 시점이다.
즉, 이 함수는 뷰가 생성 됐을때 단 한번만 실행이 된다.
이 함수 이후로 차례대로
ViewWillAppear() - 뷰가 화면에 나타날 것이다 viewDidAppear() - 뷰가 나타난 후 호출 viewWillDisappear() - 뷰가 사라지기 ‘전’ 호출 viewDidDisappear() - 뷰가 사라진 후 호출 (단, 메모리에서 없어진것은 아니다.)
이런 단계가 존재한다.
대충 스토리보드로 UI를 짜고
VC-2는 Next버튼과 직접 연결하는 직접 segue방식을 이용했다.
VC-2는 모달방식으로 나타나게 해놨다.
(방식에 따라서 호출되는 함수들이 또 다르다.)
우선 첫번째 ViewController 파일에 위에 있는 시점들을 나타내는 코드를 작성해주자
//VC-1
override func viewDidLoad() {
super.viewDidLoad()
print("VC-1 viewDidLoad")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("VC-1 viewWillAppear ")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("VC-1 viewDidAppear ")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("VC-1 viewWillDisappear ")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("VC-1 viewDidDisappear ")
}
//메모리 해제 시점을 파악
deinit {
print("VC-1 메모리에서 내려갔다.")
}
//VC-2
override func viewDidLoad() {
super.viewDidLoad()
print("@@@VC-2 viewDidLoad ")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("@@@VC-2 viewWillAppear ")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("@@@VC-2 viewDidAppear ")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("@@@VC-2 viewWillDisappear ")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("@@@VC-2 viewDidDisappear ")
}
deinit {
print("@@@VC-2 메모리에서 내려감.")
}
처음 실행하면
총 세가지 함수가 실행됨을 확인 할수 있다.
여기서 다음버튼을 누르면
VC-2에 선언한 함수들이 호출된다.
모달 방식으로 선언 되어 있기에 VC-1은 아직 사라지지 않았다.
(모달방식 상단을 자세히 보면 뒤에 바로 전화면이 보임)
만약 FullScreen방식으로 선언한다면
VC-2가 화면에 모두 표시 되고 그제서야 VC-1이 사라진다.
(단, 메모리에서는 내려가지 않은 상태이다.)
VC-2를 쓸어내리면 아래와 같이 함수가 호출 됨을 확인할수 있다.
이때는 VC-2가 완전히 메모리에서 내려간다.
만약 스토리 보드로 ui를 구성하고 loadView함수를 작성해 놓는다면
화면이 뜨지 않는 현상을 확인 할수 있다.
결론을 우선 말하자면 이 함수는 화면을 구성하면 가장 먼저 호출되는 함수이며, 뷰를 메모리에 올리는 시점이다.
즉 , 뷰를 변경할수 있는 시점이다.
만약 스토리보드로 ui를 작성한다면 해당 함수를 호출해서는 안된다.
공식문서
2번째 문단에 집중해보자
만약 ViewController에 연결돤 nib파일이 있는경우 (스토리보드 파일)
이 메서드는 view를 nib파일에서부터 로드시킨다.
스토리보가 아닌 코드베이스로 view를 생성하고 이 커스텀된 뷰를 가장 첫번째 뷰로 지정하고 싶다면
let customView = CustomView()
override func loadView() {
view = customView
}
이렇게 기존에 존재하는 view를 커스텀 뷰로 교체해주면된다.
공식문서에 따르면, 이 메서드를 커스텀 구현할 경우, 상위 클래스의 메서드 호출은 필요하지 않으며, 오히려 호출해서는 안 된다.
다른 메서드들과 달리 super.loadView() 를 호출하지 않아도, 재정의 하지 않아도 된다.
따로 이유에 대해선 공식문서에 적혀있지 않다.
Apple의 프레임워크는 일반적으로 이러한 내부 구현 세부사항을 외부에 공개하지 않는다.
어떤 시점에 화면 변경 로직을 추가해야할까?
어떤 시점이 적절할까?
화면이 나타나기전 시점 - viewWillAppear()
실제로 화면이 나타나는 시점 - viewDidAppear()
viewWillAppear() 내에 화면 색 변경 로직을 추가하면 되겠다.
여러가지 방식은 있지만 이번엔 검색하여 코드 복붙을 헀다.
(공부할게 천지라..)
출처: StackOverFlow
extension CGFloat {
static func random() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
}
extension UIColor {
static func random() -> UIColor {
return UIColor(
red: .random(),
green: .random(),
blue: .random(),
alpha: 1.0
)
}
}
CoreGarphics 프레임 워크
(2D관련 프레임워크 ,이미지, 색상관리등을 처리할수 있는 프레임 워크)
해당 프레임워크는 CG~~라는 값을 사용한다.
코드를 해석하면서 이해가 안되는 부분이
extension CGFloat {
static func random() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
이부분인데
찾아보니 arc4random()은 UInt32값중 (0~ 4,294,967,295)
랜덤 숫자를 뽑아주는 함수다.
처음에는 9년전 글이라서 오래된 코드를 사용하는게 아닌가 생각해서
자주사용하는 Int.random()과 유사하기도 하고 이걸 대신 사용해도 되는게 아닌가? 라고 생각했는데
다시 생각해보니 색상과 관련된 값이라서 굳이 메모리 용량을 더 자치하는 Int값을 쓸 이유는 없을꺼 같다.
가끔은 옛것이 좋아 보인다.