• Jan
  • Feb
  • Mar
  • Apr
  • May
  • Jun
  • Jul
  • Aug
  • Sep
  • Oct
  • Nov
  • Dec
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

DispatchQueue 궁금증 해결 완료…ㅠㅁㅠ!!!!!!

우선!

  • viewDidLoad는 main thread에서 수행되는 게 맞다.

  • View LifeCycle에서 viewDidLoad - viewWillAppear - viewDidAppear 순인데,

    viewWillAppear, viewDidAppear 사이에

    viewWillLayoutSubViews, viewDidLayoutSubViews 요 두 놈이 있다.

    그 안에서 레이아웃 수정을 다 한 후에 우리가 레이아웃 수정을 해야 제대로 반영이 된다.

예를 들어서, 오빠 코드의 viewDidLoad()에는

self.scrollView.frame.origin.y = -self.statusBarHeight!

이 있었는데, viewDidLoad()에서 실행했을 땐 안 되고, 그 안에서

DispatchQueue.main.async {
		self.scrollView.frame.origin.y = -self.statusBarHeight!
}

요런 식으로 DispatchQueue를 사용해서 main thread에서 UI 변경 작업이 수행되도록 해야지
우리가 원하는 대로 제대로 코드가 동작했었다. 아니면 viewDidAppear() 내부에 저 line을 넣어야지 동작했었다.

우리가 오해했던 것

이 stackoverflow 질문 을 보고, 아래와 같이 생각을 했다.

override func viewDidLoad() {
    super.viewDidLoad()
    firstSelector() //"First selector fired" 출력
    DispatchQueue.main.async {
        self.secondSelector() //"Second selector fired" 출력
    }
    for i in 1...10 {
        print(i)
    }
    thirdSelector() //"Third selector fired" 출력
}

이렇게 실행했을 때

First selector fired
1
2
3
4
5
6
7
8
9
10
Third selector fired
Second selector fired //DispatchQueue.main.async 블럭 내의 함수 출력

이렇게 출력되는걸로 봐서,

queue

queue에 요런 순서로 들어간 것 까지는 이해했는데, 그러면 아래와 같이 코드를 작성해도 똑같이 동작하니까,
(DispatchQueue 사용 X)

override func viewDidLoad() {
    super.viewDidLoad()
    firstSelector() //"First selector fired" 출력
    for i in 1...10 {
        print(i)
    }
    thirdSelector() //"Third selector fired" 출력
    self.secondSelector() //"Second selector fired" 출력
}

오빠 코드에 있던

self.scrollView.frame.origin.y = -self.statusBarHeight!

요놈도 viewDidLoad() 맨 아래로 내리면 똑같이 동작하지 않을까,,, 라고 생각했다.
UI수정이라 뭔가 다르겠다고 생각은 했지만, viewDidLoad() 도 main thread니까.
근데 제대로 동작 안 함.

viewDidAppear에 넣어도 동작하고,

viewDidLoad()에서 DispatchQueue 해도 동작?

여기서 답을 찾았다..!

viewDidLoad()에서 DispatchQueue.main.async 을 해준다고 해서
viewDidLoad() 내 함수의 호출들이 다 queue에 들어가고 나서
DispatchQueue.main.async 블록 내의 호출이 그 바로 다음으로 queue에 들어가는 것이 아니였다..!!!

viewDidLoad() 내에

DispatchQueue.main.async {
		self.scrollView.frame.origin.y = -self.statusBarHeight!
		print("UI 변경!")
}

이렇게 DispatchQueue 를 사용해주고,
위와 같이 각 Life cycle 함수 내부에 print문을 통해 console에 출력을 해주면,
실행 순서가 다음과 같다.

viewDidLoad -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> “UI 변경!” 출력 -> viewDidAppear

viewDidLayoutSubViews 후에 우리가 레이아웃 수정을 해야 제대로 반영이 된다는 건 알았지만,

우리가 깨달은 건,,,

viewDidLoad()에서 DispatchQueue.main.async를 한다고 해서 viewDidLoad() 안에서만 동작하는 게 아니라
UI 작업이 반영되는 타이밍까지 기다렸다가 해당 코드를 실행해주는 식으로 우선순위가 정해진다는 것!

요 부분은 QoS의 user interactive 관련인 것 같다. (내생각)

암튼… dispatchQueue 진짜 똑똑하네잉..

추가

때는 210429… 갓수진님의 도움으로 깨달음을 얻었더랬다…

viewWillAppear에서 Autolayout constraints은 제대로 세팅되지 않은 상태라고 한다. viewWillAppear 🔜 viewWillLayoutSubviews 🔜 viewDidLayoutSubviews이 constraint를 만족시키기 위해 위해 차례대로 호출되는데, 따라서 그 다음으로 불리는 viewDidAppear에서야 constraint가 잘 세팅되어 있을 것이라고.. ㅎ

DispatchQueue async 가 불리는 시점이 공교롭게도 viewDidLayoutSubviews 이후라 레이아웃이 잘 적용된 것 처럼 보인듯

한 것이었ㄷr…………..