UIKit 메인 스레드에서 실행했는데도 Alert이 안 뜨는 이유

2025. 6. 20. 20:56·🖋️ TIL Journal
-->

 

이번에 과제를 하면서 JSON 데이터를 가지고 오기 실패한 경우, Alert창으로 에러를 띄워줘야 했다.

 

하지만.. 난 Alert을 띄우는 방법을 몰라요..! 어쩌겠어.. 찾아봐야지.. 🙂‍↔️

 

그래서 우선 UIAlertController로 만들어서 present()로 띄우면 된다는 걸 알게 됐다. 

func showErrorAlert(message: String) {
    let alert = UIAlertController(title: "에러", message: message, preferredStyle: .alert)
    let ok = UIAlertAction(title: "확인", style: .default, handler: nil)
    alert.addAction(ok)
    present(alert, animated: true)
}

 

이렇게 Alert을 띄우는 메서드를 만들고, loadBooks()라는 메서드 안에서 호출하도록 했다.

func loadBooks() {
    dataService.loadBooks { [weak self] result in
        guard let self = self else { return }

        switch result {
        case .success(let books):
                        // 생략
        case .failure(let error):
            self.showErrorAlert(message: error.localizedDescription)
        }
    }
}

테스트를 위해서 JSON 데이터를 일부러 잘못 넣어서 에러가 발생하도록 했다.

 

이제 내가 원하는 결과는 책 관련된 데이터는 안보이고, Alert이 떠야했다.

 

그럼 이제.. 으잉..? 값은 없는게 맞는데.... Alert이 안뜨네..? 🫠

 

왜 안뜨니 Alert...

왜 안뜨니 Alert..

 

 

코드는 잘 돌아가고, alert 객체도 잘 만들어졌고, present()도 호출되었다. 에러 메시지도 없고, showErrorAlert()가 호출되는 것도 확인했는데… 아무런 반응이 없다.

 

알고보니, iOS에서는 UILabel, UIButton, UIAlertController 같은 UI 관련 작업은 반드시 메인 스레드에서만 실행되어야 한다는 것을 알게 되었다.

 

그리고 만약 UI 관련 작업이 메인 스레드에서 실행되지 않으면, iOS는 경고 없이 무시해버리거나, 어떤 경우에는 크래시가 날 수도 있다고 한다. (실제로는 케이스마다 다름)

 

그래서 처음엔 “아, loadBooks()가 메인 스레드에서 실행이 안되고 있구나!” 하고 생각했지만…

 

알고 보니 지금 구조에서는 loadBooks() 내부에서 비동기 처리를 따로 하지 않았기 때문에, 호출한 쪽(viewDidLoad)이 메인 스레드라면 completion도 메인 스레드에서 실행된다.

 

즉, 메인 스레드에서 실행되고 있었음에도 불구하고 Alert이 안 뜬 것이다.

 

알고보니 진짜 Alert이 안뜬 이유는 바로 UI 처리 타이밍, 즉 RunLoop 타이밍 문제 때문이었다.

 

viewDidLoad()에서 너무 이른 시점에 present()가 호출되면, UI가 아직 완전히 렌더링되기 전이라 Alert이 뜨지 않는 경우가 있을 수 있다고 한다.

 

👊 이제 해결을 해보자..!

 

해결 방법은 간단했다. present() 호출을 DispatchQueue.main.async로 감싸서 다음 RunLoop 주기에 실행되도록 예약해주면 되는 것이다.

DispatchQueue.main.async {
    self.present(alert, animated: true)
}

이렇게 코드를 수정하고 다시 실행해보니, Alert가 정상적으로 잘 나타났다. 결국 해결! 🙌

Alert!

 

✅ 이 경험을 통해 알게 된 점

  • UI 관련 코드는 메인 스레드에서 실행되어야 한다.
  • 그런데 메인 스레드라고 하더라도, present() 같은 UI 업데이트가 너무 빠르면 Alert이 안 뜰 수 있다.
  • 따라서 UI 작업은 DispatchQueue.main.async로 감싸서 RunLoop 타이밍을 조절해주는 게 안전하다.
  • Alert이 안 뜬 이유는 꼭 스레드 문제만은 아니고, UI 처리 타이밍(RunLoop) 문제일 수도 있다.

 

 

 

'🖋️ TIL Journal' 카테고리의 다른 글

[트러블 슈팅] 장바구니 셀 동적 높이 조절 + 스크롤  (0) 2025.07.01
[Swift] 프로그래머스 - 콜라스 추측 문제 풀이  (0) 2025.06.30
Xcode에서 시뮬레이터 추가하는 방법  (0) 2025.06.18
[SnapKit] offset vs inset 정리  (0) 2025.06.17
willSet / didSet 속성 감시자(Property Observers)  (0) 2025.06.16
'🖋️ TIL Journal' 카테고리의 다른 글
  • [트러블 슈팅] 장바구니 셀 동적 높이 조절 + 스크롤
  • [Swift] 프로그래머스 - 콜라스 추측 문제 풀이
  • Xcode에서 시뮬레이터 추가하는 방법
  • [SnapKit] offset vs inset 정리
MoriOS
MoriOS
기억하기 위해 기록하는 공간 🖋️
  • MoriOS
    MoriOS
    MoriOS
  • 전체
    오늘
    어제
    • 분류 전체보기 (66)
      • 📌 Swift (12)
      • 📱 iOS (9)
      • 💡 Algorithm (1)
      • ❕Data structure (4)
      • 🪙 Python (0)
      • ⚙️ Git (2)
      • 🖋️ TIL Journal (35)
      • 📝 Etc (3)
  • 블로그 메뉴

    • GitHub
  • 인기 글

  • 태그

    TiL
    후행클로저
    uikit
    Codable
    스크롤 길이
    ios
    isscrollenabled
    prepareconstraints
    셀 높이
    makeconstraint
    remakeconstraints
    cow 쓰기 복사
    swift optional
    updateconstraints
    weak
    동적 스크롤
    제약조건 변경
    동적 셀
    프로그래머스
    Optional
    GitHub
    SnapKit
    cow 값 타입
    swift
    cow 참조 타입
    static
    Split
    제약조건 수정
    Components
    swift cow
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
MoriOS
UIKit 메인 스레드에서 실행했는데도 Alert이 안 뜨는 이유
상단으로

티스토리툴바