@Published: 개념, 작동 원리 및 적용

저자: IT Sectr 게시일: 2026-06-19 읽는 시간: 8 분

@Published는 ObservableObject 프로토콜을 준수하는 클래스 속성의 변경 사항을 자동으로 게시하는 Combine 프레임워크의 property wrapper입니다. @Published로 표시된 속성의 값이 변경되면 SwiftUI는 objectWillChange를 통해 신호를 수신하고 해당 객체를 구독하는 모든 뷰를 다시 그립니다. Apple Combine 프레임워크 문서(2025)에 따르면 @Published는 Publisher를 생성하며 map, filter, debounce 등 Combine 연산자를 통해 추가로 변환할 수 있습니다. 이는 @Published를 MVVM 아키텍처에서 데이터와 사용자 인터페이스 간의 핵심 브리지로 만듭니다.

핵심 요점

  • @Published — SwiftUI 및 Combine에서 ObservableObject 속성 변경 사항을 자동으로 게시하기 위한 property wrapper
  • 메커니즘: 값이 변경되면 objectWillChange가 호출되어 구독된 뷰의 다시 그리기를 트리거합니다
  • Publisher는 프로젝션 $property를 통해 액세스 가능 — 스트림을 구독, 결합 및 변환할 수 있습니다
  • ObservedObjectStateObject는 자동으로 @Published 속성을 구독합니다 — 수동 구독이 필요하지 않습니다
  • iOS 17+ @Observable 매크로가 대안을 제공하지만 @Published는 Combine 파이프라인의 표준으로 남아 있습니다

@Published란?

@Published는 Combine 모듈에 정의된 property wrapper로, 클래스 속성의 변경 사항을 구독자에게 자동으로 알리는 기능을 추가합니다. 이는 클래스 내부에서만(구조체에서는 불가) 그리고 ObservableObject 프로토콜을 준수하는 클래스의 속성에만 사용할 수 있습니다.

@Published 속성의 값이 변경되면 Combine은 달러 접두사를 통해 액세스할 수 있는 내장 publisher를 통해 이벤트를 생성합니다: $propertyName. 이 publisher는 ObservableObject 자체에 속하는 ObservableObjectPublisher입니다. SwiftUI는 뷰가 @ObservedObject 또는 @StateObject를 사용할 때 자동으로 이를 구독하며, 객체 내의 @Published 속성이 변경될 때마다 뷰를 다시 그립니다.

Matt Neuburg의 저서 “IOS 18 Programming Fundamentals with Swift” (2025)에 따르면 @Published는 willSet 패턴의 편리한 래퍼로, 자동으로 objectWillChange.send()를 호출합니다. 실제로 컴파일러는 @Published를 willSet 관찰자가 있는 계산된 속성으로 확장하여 수동 구현에 비해 런타임 오버헤드가 없습니다.

변경 사항이 인터페이스에 반영되어야 하는 모든 ObservableObject 속성에 @Published를 사용하십시오. UI에 영향을 주지 않는 속성의 경우 @Published가 없는 일반 저장 속성을 사용하면 불필요한 다시 그리기가 줄어듭니다.

@Published 작동 방식

@Published는 컴파일 타임에 두 가지 주요 요소를 생성합니다. 첫 번째는 새 값을 쓰기 전에 objectWillChange.send()를 호출하는 willSet 관찰자가 있는 저장 속성입니다. 두 번째는 Published.Publisher를 반환하는 프로젝션 $propertyName으로, Combine 파이프라인에서 직접 사용할 수 있습니다.

세 가지 속성이 있는 Settings 클래스를 생각해 보겠습니다: 두 개의 @Published와 하나의 일반 속성:

swift
class Settings: ObservableObject {
    @Published var username: String = "Guest"
    @Published var isDarkMode = false
    var lastLogin: Date = Date()  // without @Published
}

username 또는 isDarkMode가 변경되면 SwiftUI는 Settings 인스턴스를 구독하는 모든 뷰를 다시 그립니다. lastLogin을 변경해도 다시 그리기가 트리거되지 않습니다. 일반 속성의 변경 사항을 구독자에게 수동으로 알려야 하는 경우 willSet 관찰자에서 objectWillChange.send()를 호출할 수 있습니다.

중요한 세부 사항: @Published는 속성이 직접 할당될 때만 변경 사항을 게시합니다. 속성이 참조 유형(클래스)이고 참조를 교체하지 않고 내부 상태가 변경된 경우 @Published는 이를 감지하지 못합니다. 이러한 경우 수동 이벤트 전송 또는 값 유형(구조체)으로의 전환이 필요합니다.

@Published와 Combine

@Published는 Combine과 긴밀하게 통합되어 있습니다 — 각 @Published 속성은 프로젝션 $propertyName을 통해 액세스할 수 있는 publisher를 자동으로 제공합니다. 이를 통해 필터링, 변환, 결합 및 지연된 값 처리를 위해 Combine 연산자를 사용할 수 있습니다.

일반적인 시나리오는 디바운스를 사용한 검색입니다. 입력 필드는 @Published 속성 searchText에 바인딩되어 있지만 서버 요청은 300ms 지연 후에만 전송되어야 합니다. $searchText.debounce를 사용한 Combine은 한 줄로 해결합니다:

swift
class SearchViewModel: ObservableObject {
    @Published var searchText = ""
    @Published var results: [String] = []
    private var cancellables = Set<AnyCancellable>()

    init() {
        setupSearchSubscription()
    }

    private func setupSearchSubscription() {
        $searchText
            .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
            .removeDuplicates()
            .sink { [weak self] text in
                self?.performSearch(text)
            }
            .store(in: &cancellables)
    }

    private func performSearch(_ text: String) { }
}

John Sundell의 기사(Swift by Sundell, 2024)에 따르면 @Published를 Combine과 결합하는 것은 SwiftUI 애플리케이션에서 반응형 파이프라인의 표준 패턴입니다: 유효성 검사, debounce, throttle, combineLatest, 다른 publisher와의 병합. @Published는 명령형 UI 코드와 반응형 Combine 간의 브리지 역할을 합니다.

@Published vs @Observable 매크로

iOS 17 출시와 함께 Apple은 @Observable 매크로를 도입하여 ObservableObject와 @Published 없이 반응성에 대한 대체 접근 방식을 제공합니다. @Observable은 쓰기 수준이 아닌 읽기 수준에서 속성 액세스를 자동으로 추적하여 더 정확한 다시 그리기를 제공합니다 — 특정 변경된 속성을 읽는 뷰만 업데이트됩니다.

그러나 이것이 @Published가 더 이상 사용되지 않음을 의미하지는 않습니다. @Published는 Combine 파이프라인 통합이 필요할 때 계속 필요합니다 — 프로젝션 $propertyName은 @Observable에 없는 publisher를 제공합니다. 또한 iOS 16 이하와의 하위 호환성을 위해 @Published+ObservableObject가 유일한 옵션입니다. Apple WWDC 2023 세션 “Discover Observation in SwiftUI”에 따르면 Apple은 새 프로젝트에는 @Observable을 권장하지만 기존 코드 및 Combine 시나리오에 대한 @Published 지원을 명시적으로 유지합니다.

실제로 많은 프로젝트에서 하이브리드 접근 방식을 사용합니다: 새 데이터 모델은 @Observable을 사용하고 @Published가 있는 기존 ObservableObject는 리팩터링 없이 유지됩니다. @Published는 게시에 대한 세밀한 제어가 필요할 때도 필수적입니다 — 예를 들어 여러 속성의 배치 업데이트가 완료될 때까지 알림을 지연시키는 경우입니다.

@Published 일반적인 실수

첫 번째 실수는 구조체에서 @Published 사용입니다. 컴파일러는 오류를 발생시킵니다: “Property wrapper cannot be applied to a computed property” 또는 “‘@Published’ is only available on members of a class.” ObservableObjectPublisher는 각 인스턴스에 대해 고유해야 하는 클래스이므로 @Published에는 참조 의미 체계가 필요합니다.

두 번째 실수는 참조를 교체하지 않고 참조 속성의 내용 변경입니다. @Published 속성이 배열 유형 [String]이고 array.append("new")를 호출하는 경우 배열에 대한 참조가 변경되지 않았으므로 @Published가 변경을 감지하지 못합니다. 해결책: 속성에 새 값을 할당 array = array + ["new"]하거나 수동으로 objectWillChange.send()를 사용합니다.

세 번째 실수는 @Published 속성의 과도한 수입니다. 각 @Published 속성은 해당 속성을 읽는 뷰뿐만 아니라 ObservableObject를 구독하는 모든 뷰의 다시 그리기를 트리거합니다. Point-Free (2025)에 따르면 하나의 큰 ObservableObject를 @StateObject 및 @EnvironmentObject와 함께 여러 개의 작은 ObservableObject로 분할하면 불필요한 다시 그리기가 줄어들고 성능이 향상됩니다.

코드 예제

첫 번째 예제는 유효성 검사가 있는 등록 양식 ViewModel입니다. @Published 속성 emailpassword는 Combine 파이프라인을 통해 유효성 검사 오류 표시를 트리거합니다:

swift
class RegistrationViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var emailError: String?
    @Published var isFormValid = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        $email
            .map { $0.contains("@") ? nil : "Invalid email" }
            .assign(to: &$emailError)
            .store(in: &cancellables)

        $email.combineLatest($password)
            .map { !$0.isEmpty && !$1.isEmpty }
            .assign(to: &$isFormValid)
            .store(in: &cancellables)
    }
}

두 번째 예제는 참조 요소 컬렉션에 대한 수동 게시입니다. 요소 내부의 모든 변경 사항에 대해 전체 배열을 교체하는 대신 objectWillChange.send()가 사용됩니다:

swift
class TodoItem {
    var title: String
    var isDone = false
    init(title: String) { self.title = title }
}

class TodoListViewModel: ObservableObject {
    @Published var items: [TodoItem] = []

    func toggle(item: TodoItem) {
        item.isDone.toggle()
        self.objectWillChange.send()  // manual notification
    }
}

세 번째 예제는 Combine을 통한 @Published 속성에 대한 Assign입니다. Swift 5.9의 새로운 구문을 사용하면 Optional 래퍼 없이 프로젝션 assign(to: &$property)을 통해 직접 할당할 수 있습니다. 구독을 생성하지 않고 publisher를 @Published 속성에 연결하는 가장 짧은 방법입니다.

자주 묻는 질문

@Published를 구조체에서 사용할 수 있나요?

아니요, @Published는 ObservableObject를 준수하는 클래스 내부에서만 사용할 수 있습니다. 구조체에서는 로컬 상태에 @State를 사용하거나 iOS 17+에서 @Observable 매크로와 함께 @Bindable을 사용하세요. 구조체에서 @Published를 사용하려고 하면 컴파일 오류가 발생합니다.

@Published는 배열 및 딕셔너리와 어떻게 작동하나요?

올바른 접근 방식: 새 값을 전체적으로 할당합니다(array = array + ["new"]). @Published는 내용 변경이 아닌 참조 교체를 추적합니다. 참조 유형 컬렉션의 경우 요소의 내부 상태를 변경한 후 수동으로 objectWillChange.send()를 사용하세요.

@Published와 @State의 차이점은 무엇인가요?

@State는 단일 뷰 내의 로컬 상태용으로 설계되었으며 값 유형에서만 작동합니다. @Published는 @ObservedObject 또는 @EnvironmentObject를 통해 여러 뷰에서 읽을 수 있는 ObservableObject 속성용입니다. @State는 더 간단하고 @Published는 Combine 통합 덕분에 더 강력합니다.

모든 ObservableObject 속성에 @Published가 필요한가요?

변경 사항이 UI를 업데이트해야 하는 속성만 필요합니다. 내부 계산, 캐시 또는 임시 플래그용 속성에는 @Published가 필요하지 않습니다 — 불필요한 다시 그리기가 줄어듭니다. @Published를 “이 속성은 인터페이스에 중요합니다”라는 신호로 사용하세요.

@Published는 Core Data와 어떻게 작동하나요?

SwiftUI는 NSManagedObject에 대해 @FetchRequest@ObservedObject를 통해 Core Data와 통합됩니다. ManagedObject는 이미 ObservableObject를 준수하므로 @Published가 필요하지 않습니다 — NSManagedObject가 자체적으로 변경 사항을 알립니다. @Published는 데이터 변환을 위해 Core Data와 UI 사이의 ViewModel 계층에서 사용됩니다.

요약

  • @Published — SwiftUI 및 Combine 파이프라인을 위해 ObservableObject 속성 변경을 자동으로 게시하는 Combine의 property wrapper
  • 메커니즘: willSet 관찰자가 objectWillChange.send()를 호출하여 프로젝션 $property를 통해 publisher 생성
  • Combine: @Published는 debounce, map, combineLatest 및 기타 연산자를 위한 publisher 제공 — UI와 반응형 파이프라인 간의 브리지
  • @Observable (iOS 17+) — 새 프로젝트를 위한 대안이지만 @Published는 Combine 및 하위 호환성의 표준으로 남음
  • 실수: @Published는 구조체에서 작동하지 않으며 참조 유형 변경을 추적하지 않으며 과도한 @Published 속성은 다시 그리기를 증가시킴
  • 모범 사례: UI에 영향을 미치는 속성만 @Published로 표시하고 큰 ObservableObject를 여러 개의 작은 것으로 분할
  • Assign: Swift 5.9의 assign(to: &$property)를 사용하면 publisher를 @Published 속성에 직접 구독할 수 있음

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기