๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/๐Ÿ˜ถ ๊ถ๊ธˆ์ฆ

[iOS/SwiftUI] Life Cycle

by MINT09 2025. 8. 11.

SwiftUI๋Š” ์„ ์–ธ์  UI ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, ๋ทฐ ์ž์ฒด๊ฐ€ State์— ๋ฐ˜์‘ํ•˜์—ฌ UI๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค. UIKit๊ณผ๋Š” ๋‹ฌ๋ฆฌ ViewController๊ฐ€ ์—†๊ณ , State๋ฅผ ์ค‘์‹ฌ์œผ๋กœ UI๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ช…์‹œ์  LifeCycle Method๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋•Œ๋ฌธ์— LifeCycle hook ๋Œ€์‹  ‘Modifier’๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ ์ด๋งˆ์ €๋„ UIKit์ฒ˜๋Ÿผ ์ƒ์„ธํ•˜๊ฒŒ ๋‚˜๋‰˜์ง€๋Š” ์•Š๊ณ  onAppear, onDisappear๋กœ ์ข…๋ฅ˜๊ฐ€ ํ•œ์ •์ ์ด๋‹ค.

State๊ฐ€ ๋ณ€ํ•˜๋ฉด ์ด๋ฅผ ๊ฐ์ง€ํ•ด View ์ „์ฒด๋ฅผ re-renderํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋•Œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ View๋Š” ๊ฐ’ ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝ์ ์ด ์žˆ๋Š” ๋ถ€๋ถ„๋งŒ ์žฌ๊ตฌ์„ฑ๋œ๋‹ค. ๋น„๋™๊ธฐ ์ž‘์—… ์—ญ์‹œ UIKit์€ callback, delegate, notification ๋“ฑ์„ ํ™œ์šฉํ•˜์ง€๋งŒ SwiftUI๋Š” Combine, async/await๊ณผ ์ž์—ฐ์Šค๋Ÿฌ์šด ์—ฐ๊ณ„๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

SwiftUI Life Cycle ์ƒ์„ธ ํ๋ฆ„

  1. ์•ฑ ์‹คํ–‰ → @main App Struct์˜ body ๋‚ด Scene ๊ตฌ์„ฑ์ด ์‹คํ–‰
  2. ๋ทฐ๊ฐ€ ํ™”๋ฉด์— ํ‘œ์‹œ๋  ๋•Œ onAppear modifier ์‹คํ–‰
  3. ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋˜๋ฉด ๋ทฐ ์ „์ฒด๊ฐ€ ๋‹ค์‹œ ๊ณ„์‚ฐ๋˜๊ณ  ํ™”๋ฉด ๊ฐฑ์‹ 
  4. ๋ทฐ๊ฐ€ ์‚ฌ๋ผ์งˆ ๋•Œ onDisappear ์‹คํ–‰

๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ๊ด€๋ฆฌ

SwiftUI๋Š” State ๋ณ€ํ™”๋ฅผ ์ค‘์‹ฌ์œผ๋กœ UI๋ฅผ ์„ค๊ณ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„๋™๊ธฐ ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ State์— ๋ฐ˜์˜ํ•˜๋ฉด ๊ณง๋ฐ”๋กœ ํ™”๋ฉด์— ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

Combine

ํŠนํžˆ Combine์˜ Publisher - Subscriber ๋ชจ๋ธ์„ ์ด์šฉํ•ด ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ด๋ฅผ ์‰ฝ๊ฒŒ UI ์ƒํƒœ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

import SwiftUI
import Combine

class ViewModel: ObservableObject {
    @Published var text = "Loading..."
    private var cancellables = Set<AnyCancellable>()
    
    func loadData() {
        fetchDataPublisher()
            .receive(on: DispatchQueue.main)
            .sink { completion in
                if case .failure(let error) = completion {
                    self.text = "Error: \\(error.localizedDescription)"
                }
            } receiveValue: { value in
                self.text = value
            }
            .store(in: &cancellables)
    }
    
    func fetchDataPublisher() -> AnyPublisher<String, Error> {
        Just("Hello from Combine!")
            .delay(for: .seconds(2), scheduler: DispatchQueue.global())
            .setFailureType(to: Error.self)
            .eraseToAnyPublisher()
    }
}

struct CombineView: View {
    @StateObject private var vm = ViewModel()
    
    var body: some View {
        Text(vm.text)
            .onAppear {
                vm.loadData()
            }
    }
}

async / await

๋˜ํ•œ SwiftUI๋Š” async-await ๋ฌธ๋ฒ•์„ ์ง์ ‘ View์—์„œ task modifier์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด, ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. UIKit์—์„œ๋Š” ๋น„๋™๊ธฐ ์ž‘์—… ์ดํ›„ UI ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋ณ„๋„๋กœ ๋ณด๋‚ด๋Š” ๋“ฑ์˜ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ SwiftUI๋Š” ์ƒํƒœ ๋ฐ”์ธ๋”ฉ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

import SwiftUI

struct AsyncView: View {
    @State private var text: String = "Loading..."
    
    var body: some View {
        Text(text)
            .task {
                await loadData()
            }
    }
    
    func loadData() async {
        do {
            let result = try await fetchData()
            text = result  // ์ƒํƒœ ๋ณ€๊ฒฝ → UI ์ž๋™ ๊ฐฑ์‹ 
        } catch {
            text = "Error: \\(error.localizedDescription)"
        }
    }
    
    func fetchData() async throws -> String {
        try await Task.sleep(nanoseconds: 2 * 1_000_000_000)  // 2์ดˆ ์ง€์—ฐ
        return "Hello from async/await!"
    }
}

๋ถˆ๋ช…ํ™•์„ฑ

๋‹ค๋งŒ SwiftUI๋Š” ๋ช…์‹œ์  LifeCycle์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ์— rendering์ด ์”นํ˜€ ํ™”๋ฉด์ด ๊ฐฑ์‹ ๋˜์ง€ ์•Š๊ฑฐ๋‚˜, UI ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์ด๋Š” SwiftUI์—์„œ State์— ๋”ฐ๋ผ View๋ฅผ ์ž๋™์œผ๋กœ ๊ทธ๋ ค์ฃผ๊ธฐ์—, ๋‚ด๋ถ€์ ์œผ๋กœ ์–ธ์ œ ๋ทฐ๊ฐ€ ๋‹ค์‹œ re-render ๋˜๋Š”์ง€, ์–ด๋–ค ์‹œ์ ์— View์˜ LifeCycle ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”์ง€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ˆ์ธกํ•˜์—ฌ ์ง์ ‘ ์ œ์–ดํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, UIKit๊ณผ๋Š” ๋‹ฌ๋ฆฌ SwiftUI๋Š” View์˜ LifeCycle ๊ด€๋ฆฌ๊ฐ€ ๊ฐ„์ ‘์ ์ด๊ณ  ์ถ”์ƒํ™”๋˜์–ด ์žˆ๋‹ค.

๋Œ€ํ‘œ์ ์ธ ๋ฌธ์ œ๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

1. State ๋ณ€๊ฒฝ ๊ฐ์ง€ ์‹คํŒจ

SwiftUI๋Š” @State, @StateObject ๋“ฑ์˜ State Property๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๋ทฐ๋ฅผ ๋‹ค์‹œ ๊ทธ๋ฆฐ๋‹ค. (re-render) ๋•Œ๋ฌธ์— ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ SwiftUI๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋žœ๋”๋ง ๊ฐฑ์‹ ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋ฐ ์ƒํƒœ๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋‚ด๋ถ€ ํ”„๋กœํผํ‹ฐ๋งŒ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜, ์ฐธ์กฐ ํƒ€์ž… ๋‚ด๋ถ€ ์†์„ฑ์ด ๋ณ€ํ–ˆ๋Š”๋ฐ @Published๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋•Œ ๋ชจ๋“  ์ƒํƒœ๋“ค์ด State Property๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ํ™•์ธ์ด ํ•„์š”ํ•˜๋‹ค.

2. View์˜ Identity ์ถฉ๋Œ

SwiftUI๋Š” View๋ฅผ ๊ฐ’ ํƒ€์ž…์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ๋‚ด๋ถ€์ ์œผ๋กœ View์˜ id๋‚˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ์ด๋ฅผ ๋‹ค์‹œ ๊ทธ๋ฆด์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•œ๋‹ค. id๊ฐ€ ์—†๊ฑฐ๋‚˜, ๋™์ผํ•œ id๊ฐ€ ์žฌ์‚ฌ์šฉ ๋  ๋•Œ, SwiftUI๊ฐ€ View๋ฅผ ๊ฐฑ์‹ ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ List๋‚˜ ForEach์—์„œ ๊ณ ์œ ํ•œ id๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์•„ ๋ˆ„๋ฝ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์ด๋Š” ๋ณดํ†ต id: \.self ๋‚˜ ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๋ฅผ ๋ช…์‹œํ•ด์ฃผ๋ฉด ํ•ด๊ฒฐ๋œ๋‹ค.

3. ๋น„๋™๊ธฐ ์ž‘์—…๊ณผ View State ๋ถˆ์ผ์น˜

๋น„๋™๊ธฐ ์ž‘์—… ์ค‘์— View๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒฝ์šฐ, ์ด์ „ ์ž‘์—… ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜์˜๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ์ž‘์—… ์™„๋ฃŒ ์‹œ์ ์— View๊ฐ€ ์ด๋ฏธ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ฌ๋ผ์ง„ ๊ฒฝ์šฐ UI ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฌด์‹œ๋˜๋Š” ํ˜„์ƒ์ด ์ƒ๊ธด๋‹ค. @State ๋ณ€๊ฒฝ ์‹œ View์˜ ์œ ํšจ์„ฑ ํ™•์ธ์ด ํ•„์š”ํ•˜๋‹ค.

4. View ์žฌ์‚ฌ์šฉ & ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”

SwiftUI๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ํ•„์š” ์—†๋Š” View๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•˜๊ฑฐ๋‚˜ ๋‹ค์‹œ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋•Œ onAppear, onDisappear modifier๊ฐ€ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ œ์–ดํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด View๊ฐ€ ์žฌ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜, ์žฌ์‚ฌ์šฉ๋˜๋ฉด์„œ ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•˜๊ฒŒ onAppear, onDisappear์— ๋„ฃ์—ˆ๋˜ ๋กœ์ง์ด ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœ๋˜๊ฒŒ ๋œ๋‹ค. ๋•Œ๋ฌธ์— ํ•ญ์ƒ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•ด์„œ ์ค‘๋ณต ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.