@Published: คืออะไร หลักการทำงานและการประยุกต์ใช้

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-19 เวลาอ่าน: 8 นาที

@Published คือ property wrapper จากเฟรมเวิร์ก Combine ที่เผยแพร่การเปลี่ยนแปลงของคุณสมบัติของคลาสที่สอดคล้องกับโปรโตคอล ObservableObject โดยอัตโนมัติ เมื่อค่าของคุณสมบัติที่ถูกทำเครื่องหมายด้วย @Published เปลี่ยนแปลง SwiftUI จะรับสัญญาณผ่าน objectWillChange และวาดวิวทั้งหมดที่สมัครรับข้อมูลอ็อบเจ็กต์นั้นใหม่ ตามเอกสาร Apple Combine Framework (2025) @Published สร้าง Publisher ที่สามารถแปลงเพิ่มเติมได้ผ่านโอเปอเรเตอร์ Combine: map, filter, debounce และอื่น ๆ ทำให้ @Published เป็นสะพานสำคัญระหว่างข้อมูลและส่วนติดต่อผู้ใช้ในสถาปัตยกรรม MVVM

ประเด็นสำคัญ

  • @Published — property wrapper สำหรับการเผยแพร่การเปลี่ยนแปลงคุณสมบัติ ObservableObject โดยอัตโนมัติใน SwiftUI และ Combine
  • กลไก: เมื่อค่าเปลี่ยน objectWillChange จะถูกเรียก ซึ่งจะกระตุ้นการวาดวิวที่สมัครรับข้อมูลใหม่
  • Publisher สามารถเข้าถึงได้ผ่านโปรเจคชัน $property — สามารถสมัคร รวม และแปลงสตรีมได้
  • ObservedObject และ StateObject จะสมัครรับข้อมูลคุณสมบัติ @Published โดยอัตโนมัติ — ไม่จำเป็นต้องสมัครด้วยตนเอง
  • iOS 17+ มาโคร @Observable มีทางเลือกอื่น แต่ @Published ยังคงเป็นมาตรฐานสำหรับไปป์ไลน์ Combine

@Published คืออะไร?

@Published คือ property wrapper ที่กำหนดในโมดูล Combine ซึ่งเพิ่มความสามารถในการแจ้งผู้สมัครรับข้อมูลโดยอัตโนมัติเกี่ยวกับการเปลี่ยนแปลงของคุณสมบัติของคลาส สามารถใช้ได้เฉพาะภายในคลาสเท่านั้น (ไม่ใช้ในโครงสร้าง) และเฉพาะกับคุณสมบัติของคลาสที่สอดคล้องกับโปรโตคอล ObservableObject

เมื่อค่าคุณสมบัติ @Published เปลี่ยนแปลง Combine จะสร้างอีเวนต์ผ่าน publisher ในตัวที่เข้าถึงได้ผ่านคำนำหน้า dollar: $propertyName publisher นี้คือ ObservableObjectPublisher ซึ่งเป็นของ ObservableObject เอง SwiftUI จะสมัครรับข้อมูลโดยอัตโนมัติเมื่อวิวใช้ @ObservedObject หรือ @StateObject และวาดวิวใหม่เมื่อใดก็ตามที่คุณสมบัติ @Published ภายในอ็อบเจ็กต์เปลี่ยนแปลง

ตามหนังสือของ Matt Neuburg “IOS 18 Programming Fundamentals with Swift” (2025) @Published เป็น wrapper ที่สะดวกบนแพทเทิร์น willSet ซึ่งเรียก objectWillChange.send() โดยอัตโนมัติ จริง ๆ แล้ว คอมไพเลอร์ขยาย @Published เป็น computed property พร้อม willSet observer ซึ่งให้ค่าใช้จ่ายรันไทม์เป็นศูนย์เมื่อเทียบกับการใช้งานด้วยตนเอง

ใช้ @Published สำหรับคุณสมบัติ ObservableObject ทั้งหมดที่การเปลี่ยนแปลงควรสะท้อนในส่วนติดต่อ สำหรับคุณสมบัติที่ไม่ส่งผลต่อ UI การใช้ stored properties ปกติโดยไม่มี @Published จะลดการวาดใหม่ที่ไม่จำเป็น

@Published ทำงานอย่างไร

@Published สร้างองค์ประกอบหลักสองอย่างในเวลาคอมไพล์ อย่างแรกคือ stored property พร้อม willSet observer ที่เรียก objectWillChange.send() ก่อนเขียนค่าใหม่ อย่างที่สองคือโปรเจคชัน $propertyName ซึ่งส่งคืน Published.Publisher ที่สามารถใช้ได้โดยตรงในไปป์ไลน์ 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 จะไม่กระตุ้นการวาดใหม่ หากคุณต้องการแจ้งผู้สมัครรับข้อมูลด้วยตนเองเกี่ยวกับการเปลี่ยนแปลงคุณสมบัติปกติ คุณสามารถเรียก objectWillChange.send() ใน willSet observer

รายละเอียดสำคัญ: @Published เผยแพร่การเปลี่ยนแปลงเฉพาะเมื่อมีการกำหนดค่าให้คุณสมบัติโดยตรง หากคุณสมบัติเป็นชนิดอ้างอิง (คลาส) และสถานะภายในเปลี่ยนแปลงโดยไม่แทนที่การอ้างอิง @Published จะไม่ตรวจพบ ในกรณีเช่นนี้ จำเป็นต้องส่งอีเวนต์ด้วยตนเองหรือเปลี่ยนเป็นชนิดค่า (โครงสร้าง)

@Published และ Combine

@Published ถูกรวมเข้ากับ Combine อย่างแน่นหนา — แต่ละคุณสมบัติ @Published จะให้ publisher โดยอัตโนมัติที่เข้าถึงได้ผ่านโปรเจคชัน $propertyName ซึ่งอนุญาตให้ใช้โอเปอเรเตอร์ Combine สำหรับการกรอง การแปลง การรวม และการประมวลผลค่าที่เลื่อนออกไป

สถานการณ์ทั่วไปคือการค้นหาแบบ debounce ฟิลด์อินพุตถูกผูกกับคุณสมบัติ @Published searchText แต่คำขอไปยังเซิร์ฟเวอร์ควรส่งหลังจากหยุด 300 มิลลิวินาทีเท่านั้น Combine กับ $searchText.debounce แก้ปัญหานี้ในบรรทัดเดียว:

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, merge กับ publishers อื่น @Published ทำหน้าที่เป็นสะพานระหว่างโค้ด UI แบบจำเป็นและ Combine แบบเชิงโต้ตอบ

@Published กับมาโคร @Observable

ด้วยการเปิดตัว iOS 17 Apple ได้แนะนำมาโคร @Observable ซึ่งนำเสนอวิธีการอื่นสำหรับการโต้ตอบโดยไม่ต้องใช้ ObservableObject และ @Published @Observable จะติดตามการเข้าถึงคุณสมบัติโดยอัตโนมัติในระดับการอ่านแทนการเขียน ให้การวาดใหม่ที่แม่นยำยิ่งขึ้น — เฉพาะวิวที่อ่านคุณสมบัติที่เปลี่ยนแปลงเท่านั้นที่ถูกอัปเดต

อย่างไรก็ตาม นี่ไม่ได้หมายความว่า @Published ล้าสมัย @Published ยังคงจำเป็นเมื่อต้องการการรวมไปป์ไลน์ Combine — โปรเจคชัน $propertyName ให้ publisher ที่ @Observable ไม่มี นอกจากนี้ สำหรับความเข้ากันได้ย้อนหลังกับ iOS 16 และต่ำกว่า @Published+ObservableObject เป็นตัวเลือกเดียว ตามเซสชัน Apple WWDC 2023 “Discover Observation in SwiftUI” Apple แนะนำ @Observable สำหรับโปรเจกต์ใหม่ แต่ยังคงสนับสนุน @Published อย่างชัดเจนสำหรับโค้ดที่มีอยู่และสถานการณ์ Combine

ในทางปฏิบัติ หลายโปรเจกต์ใช้วิธีการแบบผสม: โมเดลข้อมูลใหม่ใช้ @Observable ในขณะที่ ObservableObject ที่มีอยู่กับ @Published ยังคงอยู่โดยไม่ปรับโครงสร้าง @Published ยังเป็นสิ่งจำเป็นเมื่อต้องการควบคุมการเผยแพร่อย่างละเอียด — ตัวอย่างเช่น เลื่อนการแจ้งเตือนจนกว่าการอัปเดตแบบแบตช์ของคุณสมบัติหลายอย่างจะเสร็จสมบูรณ์

ข้อผิดพลาดทั่วไปกับ @Published

ข้อผิดพลาดแรกคือ การใช้ @Published ในโครงสร้าง คอมไพเลอร์จะแสดงข้อผิดพลาด: “Property wrapper cannot be applied to a computed property” หรือ “‘@Published’ is only available on members of a class.” @Published ต้องมีความหมายแบบอ้างอิงเพราะ ObservableObjectPublisher เป็นคลาสที่ต้องไม่ซ้ำกันสำหรับแต่ละอินสแตนซ์

ข้อผิดพลาดที่สองคือ การเปลี่ยนเนื้อหาของคุณสมบัติอ้างอิง โดยไม่แทนที่การอ้างอิง หากคุณสมบัติ @Published เป็นชนิดอาร์เรย์ [String] และคุณเรียก array.append("ใหม่") @Published จะไม่ตรวจพบการเปลี่ยนแปลงเนื่องจากการอ้างอิงถึงอาร์เรย์ไม่เปลี่ยนแปลง วิธีแก้: กำหนดค่าใหม่ให้คุณสมบัติ array = array + ["ใหม่"] หรือใช้ objectWillChange.send() ด้วยตนเอง

ข้อผิดพลาดที่สามคือ จำนวนคุณสมบัติ @Published มากเกินไป แต่ละคุณสมบัติ @Published จะกระตุ้นการวาดใหม่ของวิวทั้งหมดที่สมัครรับข้อมูล ObservableObject ไม่ใช่เฉพาะวิวที่อ่านคุณสมบัตินั้น ตาม Point-Free (2025) การแบ่ง ObservableObject ขนาดใหญ่หนึ่งอันเป็นอันเล็กหลายอันด้วย @StateObject และ @EnvironmentObject ช่วยลดการวาดใหม่ที่ไม่จำเป็นและปรับปรุงประสิทธิภาพ

ตัวอย่างโค้ด

ตัวอย่างแรกคือ ViewModel ของฟอร์มลงทะเบียน พร้อมการตรวจสอบ คุณสมบัติ @Published email และ password กระตุ้นการแสดงข้อผิดพลาดการตรวจสอบผ่านไปป์ไลน์ 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
    }
}

ตัวอย่างที่สามคือ Assign ไปยังคุณสมบัติ @Published ผ่าน Combine การใช้ไวยากรณ์ Swift 5.9 ใหม่ คุณสามารถกำหนดโดยตรงผ่านโปรเจคชัน assign(to: &$property) โดยไม่ต้องใช้ Optional wrapper นี่เป็นวิธีที่สั้นที่สุดในการเชื่อมต่อ publisher กับคุณสมบัติ @Published โดยไม่ต้องสร้างการสมัครรับข้อมูล

คำถามที่พบบ่อย

สามารถใช้ @Published ในโครงสร้างได้หรือไม่?

ไม่ @Published สามารถใช้ได้เฉพาะภายในคลาสที่สอดคล้องกับ ObservableObject ในโครงสร้าง ให้ใช้ @State สำหรับสถานะภายในหรือ @Bindable กับมาโคร @Observable ใน iOS 17+ การพยายามใช้ @Published ในโครงสร้างจะทำให้เกิดข้อผิดพลาดในการคอมไพล์

@Published ทำงานกับอาร์เรย์และดิกชันนารีอย่างไร?

วิธีการที่ถูกต้อง: กำหนดค่าใหม่ทั้งหมด (array = array + ["ใหม่"]) @Published ติดตามการแทนที่การอ้างอิง ไม่ใช่การเปลี่ยนแปลงเนื้อหา สำหรับคอลเลกชันของชนิดอ้างอิง ให้ใช้การเรียก objectWillChange.send() ด้วยตนเองหลังจากเปลี่ยนสถานะภายในขององค์ประกอบ

@Published แตกต่างจาก @State อย่างไร?

@State ออกแบบมาสำหรับสถานะภายในวิวเดียวและทำงานกับชนิดค่าเท่านั้น @Published สำหรับคุณสมบัติ ObservableObject ที่สามารถอ่านได้โดยหลายวิวผ่าน @ObservedObject หรือ @EnvironmentObject @State ง่ายกว่า @Published มีประสิทธิภาพมากกว่าด้วยการรวม Combine

ทุกคุณสมบัติ ObservableObject จำเป็นต้องมี @Published หรือไม่?

เฉพาะคุณสมบัติที่ การเปลี่ยนแปลงควรอัปเดต UI คุณสมบัติสำหรับการคำนวณภายใน แคช หรือแฟล็กชั่วคราวไม่จำเป็นต้องมี @Published — ซึ่งช่วยลดการวาดใหม่ที่ไม่จำเป็น ใช้ @Published เป็นสัญญาณว่า “คุณสมบัตินี้สำคัญสำหรับส่วนติดต่อ”

@Published ทำงานกับ Core Data อย่างไร?

SwiftUI รวมกับ Core Data ผ่าน @FetchRequest และ @ObservedObject สำหรับ NSManagedObject ManagedObject สอดคล้องกับ ObservableObject อยู่แล้ว ดังนั้นไม่จำเป็นต้องใช้ @Published — NSManagedObject แจ้งการเปลี่ยนแปลงด้วยตัวเอง @Published ใช้ในเลเยอร์ ViewModel ระหว่าง Core Data และ UI สำหรับการแปลงข้อมูล

สรุป

  • @Published — property wrapper จาก Combine ที่เผยแพร่การเปลี่ยนแปลงคุณสมบัติ ObservableObject โดยอัตโนมัติสำหรับ SwiftUI และไปป์ไลน์ Combine
  • กลไก: willset observer เรียก objectWillChange.send() สร้าง publisher ผ่านโปรเจคชัน $property
  • Combine: @Published ให้ publisher สำหรับ debounce, map, combineLatest และโอเปอเรเตอร์อื่น ๆ — สะพานระหว่าง UI และไปป์ไลน์เชิงโต้ตอบ
  • @Observable (iOS 17+) — ทางเลือกสำหรับโปรเจกต์ใหม่ แต่ @Published ยังคงเป็นมาตรฐานสำหรับ Combine และความเข้ากันได้ย้อนหลัง
  • ข้อผิดพลาด: @Published ไม่ทำงานในโครงสร้าง ไม่ติดตามการเปลี่ยนแปลงชนิดอ้างอิง คุณสมบัติ @Published มากเกินไปเพิ่มการวาดใหม่
  • แนวทางปฏิบัติที่ดีที่สุด: ทำเครื่องหมายเฉพาะคุณสมบัติที่ส่งผลต่อ UI ด้วย @Published แบ่ง ObservableObject ขนาดใหญ่เป็นอันเล็กหลายอัน
  • Assign: assign(to: &$property) ใน Swift 5.9 อนุญาตให้สมัคร publisher โดยตรงกับคุณสมบัติ @Published

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม