willSet และ didSet คือผู้สังเกตการณ์คุณสมบัติ (property observers) ใน Swift ที่ช่วยให้สามารถรันโค้ดก่อนและหลังการเปลี่ยนแปลงค่าของคุณสมบัติ ต่างจาก computed properties ตรงที่ผู้สังเกตการณ์ไม่ได้คำนวณค่าใหม่ แต่เพียงตอบสนองต่อการเปลี่ยนแปลงเท่านั้น ตามเอกสารของ Apple, The Swift Programming Language (2026) ผู้สังเกตการณ์เป็นสิ่งที่ขาดไม่ได้สำหรับการตรวจสอบความถูกต้องของข้อมูล การซิงโครไนซ์อินเทอร์เฟซ และการบันทึกการเปลี่ยนแปลงในโค้ด
ประเด็นสำคัญ
willSet และ didSet คือผู้สังเกตการณ์คุณสมบัติ (property observers) ใน Swift ซึ่งเป็นกลไกในตัวสำหรับติดตามการเปลี่ยนแปลงของ stored properties
ต่างจากภาษาที่อื่นที่ต้องมีการใช้งาน setter ด้วยตนเองหรือระบบ callback Swift มีไวยากรณ์แบบประกาศ (declarative) สำหรับตอบสนองต่อการเปลี่ยนแปลง ผู้สังเกตการณ์จะถูกเพิ่มหลังจากการประกาศคุณสมบัติโดยตรง และไม่จำเป็นต้องเรียกแยกต่างหาก
ตามเอกสารสำหรับนักพัฒนา Apple (2026) property observers รองรับ stored properties ของคลาส โครงสร้าง หรือการแจกแจงใด ๆ พวกมันไม่ทำงานกับ computed properties เพราะคุณสมบัติเหล่านี้ไม่ได้เก็บค่า — สำหรับพวกมัน การตอบสนองต่อการเปลี่ยนแปลงจะถูกใช้งานโดยตรงใน setter
willSet ถูกเรียกทันทีก่อนกำหนดค่าใหม่ให้กับคุณสมบัติ ภายใน willSet มีพารามิเตอร์โดยนัย newValue ซึ่งมีค่าที่จะถูกตั้งค่า ในขณะนี้ ค่าปัจจุบันของคุณสมบัติยังไม่เปลี่ยนแปลง — คุณสามารถอ่านค่าเก่าได้โดยตรงผ่านคุณสมบัติ
ตามข้อเสนอ Swift Evolution SE-0001 (2024) willSet ให้ความสามารถในการดำเนินการตรวจสอบความถูกต้องหรือบันทึกก่อนการเปลี่ยนแปลงจริง ถ้ามีข้อยกเว้นถูกโยนใน willSet ค่าใหม่จะไม่ถูกนำไปใช้ ทำให้ผู้สังเกตการณ์เป็นกลไกป้องกันข้อมูล
didSet ถูกเรียกทันทีหลังจากกำหนดค่าใหม่ ภายใน didSet มีพารามิเตอร์โดยนัย oldValue ซึ่งมีค่าก่อนการเปลี่ยนแปลง ในจุดนี้ คุณสมบัติมีค่าใหม่แล้ว และคุณสามารถเปรียบเทียบกับค่าเก่าได้
ตาม Swift by Sundell (2025) didSet เป็นผู้สังเกตการณ์ที่ได้รับความนิยมมากที่สุดเพราะมักจำเป็นที่สุดสำหรับการประมวลผลภายหลัง: การอัปเดตอินเทอร์เฟซผู้ใช้ การคำนวณฟิลด์ที่ขึ้นอยู่กับใหม่ หรือการส่งข้อมูลไปยังเซิร์ฟเวอร์หลังจากการเปลี่ยนแปลง
Property observers ถูกประกาศทันทีหลังจากคุณสมบัติโดยใช้วงเล็บปีกกา ไวยากรณ์ขั้นต่ำต้องการผู้สังเกตการณ์เพียงตัวเดียว แต่คุณสามารถประกาศทั้งสองได้
var score: Int = 0 {
willSet {
print("คะแนนจะเปลี่ยนเป็น \(newValue)")
}
didSet {
print("คะแนนเปลี่ยนจาก \(oldValue) เป็น \(score)")
}
}
ทั้งสอง ผู้สังเกตการณ์เป็นตัวเลือก — คุณสามารถระบุเฉพาะ willSet หรือเฉพาะ didSet สำหรับ willSet คุณสามารถเปลี่ยนชื่อ newValue โดยการระบุชื่อในวงเล็บ
var username: String = "guest" {
willSet(newName) {
print("กำลังจะตั้งค่า \(newName)")
}
didSet(oldName) {
print("เดิมคือ \(oldName) ตอนนี้คือ \(username)")
}
}
ตาม Swift Language Guide (2026) การเปลี่ยนชื่อพารามิเตอร์ช่วยปรับปรุงความสามารถในการอ่านโค้ด โดยเฉพาะเมื่อคุณสมบัติและผู้สังเกตการณ์ถูกใช้ในโปรเจ็กต์ขนาดใหญ่ที่มีชื่อยาว
ลำดับการทำงานถูกกำหนดอย่างเคร่งครัด: อันดับแรก willSet (ค่าเก่าพร้อมใช้งาน) จากนั้นกำหนดค่า จากนั้น didSet (ค่าใหม่พร้อมใช้งาน)
class Temperature {
var celsius: Double = 0.0 {
willSet {
print("อุณหภูมิจะเปลี่ยนจาก \(celsius) เป็น \(newValue)")
}
didSet {
if celsius > 100.0 {
print("เกินจุดเดือดแล้ว!")
}
}
}
}
ข้อจำกัดที่สำคัญ: ผู้สังเกตการณ์จะไม่ถูกเรียกระหว่างการเริ่มต้นคุณสมบัติเมื่อสร้างอินสแตนซ์ ภายใน init การกำหนดค่าไม่ทริกเกอร์ willSet และ didSet — ซึ่งป้องกันผลข้างเคียงที่ไม่พึงประสงค์ในขั้นตอนการสร้าง
ตาม Apple Swift Blog (2025) พฤติกรรมนี้แตกต่างจากหลายภาษาที่ setter ถูกเรียกแม้ในคอนสตรัคเตอร์ Swift เลือกความปลอดภัย: ผู้สังเกตการณ์จะเริ่มทำงานหลังจากเสร็จสิ้นการเริ่มต้นวัตถุเท่านั้น
การเปลี่ยนแปลงคุณสมบัติภายใน didSet อาจทำให้เกิดการเรียกผู้สังเกตการณ์ซ้ำ ๆ Swift ไม่บล็อกการเรียกซ้ำ — โปรแกรมเมอร์ต้องควบคุมด้วยตนเอง
var counter: Int = 0 {
didSet {
if counter < 5 {
counter += 1
}
}
}
โค้ดเช่นนี้จะสร้างการเรียกซ้ำทั้งหมดพร้อมสแต็กโอเวอร์โฟลว์หากไม่มีเงื่อนไขออก ตามชุมชน Stack Overflow Swift (2025) นี่เป็นหนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดที่ผู้เริ่มต้นทำเมื่อทำงานกับ property observers
โครงสร้างรองรับ willSet และ didSet สำหรับ stored โดยไม่มีข้อจำกัด สิ่งสำคัญคือต้องจำว่าโครงสร้างเป็นชนิดค่า (value types) และการแก้ไขคุณสมบัติภายในเมธอด mutating ก็ทริกเกอร์ผู้สังเกตการณ์เช่นกัน
struct Point {
var x: Double = 0.0 {
didSet {
print("X เปลี่ยนเป็น \(x)")
}
}
var y: Double = 0.0 {
didSet {
print("Y เปลี่ยนเป็น \(y)")
}
}
}
var point = Point()
point.x = 5.0
ผู้สังเกตการณ์คุณสมบัติถูกใช้ในโปรเจ็กต์ Swift สำหรับงานที่หลากหลาย: ตั้งแต่การซิงโครไนซ์อินเทอร์เฟซผู้ใช้ไปจนถึงการตรวจสอบข้อมูลและการบันทึก
didSet ช่วยให้คุณย้อนกลับหรือแก้ไขค่าที่ไม่ถูกต้องทันทีหลังจากตั้งค่า ซึ่งแทนที่ setter ที่ยุ่งยากใน Objective-C และรับประกันความสมบูรณ์ของข้อมูลในระดับโมเดล
var age: Int = 0 {
didSet {
if age < 0 || age > 150 {
age = oldValue
}
}
}
เมื่อคุณสมบัติที่เกี่ยวข้องเปลี่ยนแปลง คุณสามารถอัปเดตองค์ประกอบอินเทอร์เฟซโดยอัตโนมัติโดยไม่ต้องเรียกเมธอดอัปเดตแยกต่างหาก
var userName: String = "" {
didSet {
nameLabel.text = userName
}
}
willSet สะดวกสำหรับการบันทึกเพื่อวัตถุประสงค์ในการดีบักหรือตรวจสอบ คุณสามารถบันทึกเวลาและค่าใหม่ก่อนที่จะถูกนำไปใช้ เพื่อให้แน่ใจว่าล็อกมีข้อมูลต้นฉบับสำหรับการวิเคราะห์
ตาม objc.io (2025) property observers มีประโยชน์อย่างยิ่งในสถาปัตยกรรมที่มีการไหลของข้อมูลทิศทางเดียว ซึ่งทุกการเปลี่ยนแปลงคุณสมบัติจะถูกบันทึกสำหรับการสร้างสถานะใหม่ในภายหลัง
Computed properties คำนวณค่าทันทีและไม่มีพื้นที่จัดเก็บ ในขณะที่ willSet และ didSet ทำงานบน stored property ที่มีค่าจริง
| ลักษณะ | Property Observers | Computed Properties |
|---|---|---|
| เก็บค่า | ใช่ | ไม่ |
| รันโค้ดเมื่อเปลี่ยนแปลง | ใช่ | ไม่ |
| ประเภทการประกาศ | var | var (get/set) |
| พารามิเตอร์การเข้าถึง | newValue, oldValue | newValue (ใน set) |
| การเริ่มต้น | ต้องการค่าเริ่มต้น | ไม่ต้องการ |
ความแตกต่างสำคัญ: computed property คำนวณค่าในทุกการเข้าถึง ในขณะที่ property observer ตอบสนองต่อการเปลี่ยนแปลงของค่าที่มีอยู่ การเลือกระหว่างพวกมันขึ้นอยู่กับความหมาย — ถ้าคุณสมบัติได้มาจากข้อมูลอื่น ให้ใช้ computed ถ้ามันเป็นค่าอิสระที่ต้องสังเกตการเปลี่ยนแปลง ให้ใช้ willSet/didSet
ข้อผิดพลาดที่พบบ่อยที่สุดคือการเรียก didSet แบบเรียกซ้ำโดยไม่มีเงื่อนไขออก ทุกการเปลี่ยนแปลงคุณสมบัติภายใน didSet จะทริกเกอร์ผู้สังเกตการณ์อีกครั้ง นำไปสู่ลูปไม่สิ้นสุด
ข้อผิดพลาดที่พบบ่อยอันดับสองคือการพยายามใช้ผู้สังเกตการณ์บนคุณสมบัติ let คอมไพเลอร์ Swift จะแสดงข้อผิดพลาดเพราะ let เป็นค่าคงที่
ข้อผิดพลาดที่สามคือการละเลยว่าผู้สังเกตการณ์จะไม่ถูกเรียกระหว่างการเริ่มต้น นักพัฒนาที่คาดหวังว่า willSet จะทำงานภายใน init จะได้รับพฤติกรรมที่ไม่คาดคิด
ปัญหาที่สี่คือการประยุกต์ใช้ผู้สังเกตการณ์กับคุณสมบัติใน extension Swift ห้ามเพิ่ม willSet/didSet ให้กับ stored properties ใน extension
ตาม Ray Wenderlich (2025) การเข้าใจข้อจำกัดเหล่านี้ช่วยหลีกเลี่ยงข้อบกพร่องในระยะเริ่มต้นและทำให้โค้ด Swift คาดการณ์ได้มากขึ้น
คำถามที่พบบ่อย
ได้ ผู้สังเกตการณ์แต่ละตัวเป็นตัวเลือก คุณสามารถประกาศเฉพาะ willSet เฉพาะ didSet หรือทั้งสองอย่างพร้อมกัน
ไม่ Swift ห้ามเพิ่ม willSet และ didSet ใน extension สำหรับ stored properties ผู้สังเกตการณ์จะถูกประกาศเฉพาะในนิยามชนิดดั้งเดิมเท่านั้น
ไม่ ระหว่างการเริ่มต้น ผู้สังเกตการณ์จะไม่ถูกเรียก นี่เป็นกลไกป้องกันที่ป้องกันผลข้างเคียงในขั้นตอนการสร้างวัตถุ
willSet คือผู้สังเกตการณ์ stored property ที่ทำงานก่อนการเปลี่ยนแปลงค่า setter ใน computed property เป็นวิธีคำนวณค่าใหม่ ไม่ใช่การสังเกตค่าที่มีอยู่
การเรียก didSet ซ้ำจะทำให้เกิดการเรียกซ้ำ หากไม่มีเงื่อนไขออก จะนำไปสู่สแต็กโอเวอร์โฟลว์และการสิ้นสุดโปรแกรม
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม