OperationQueue คือคิวงานระดับสูงใน iOS และ macOS ที่สร้างขึ้นบน Grand Central Dispatch ตามเอกสารของ Apple Developer, 2026 OperationQueue จัดการอินสแตนซ์ของ Operation ซึ่งเป็นออบเจ็กต์ที่ห่อหุ้มหน่วยการทำงาน แตกต่างจาก DispatchQueue ตรงที่ OperationQueue รองรับการพึ่งพาระหว่างการดำเนินการ ลำดับความสำคัญ การสังเกต KVO และการยกเลิกงานที่กำลังทำงาน OperationQueue จัดการพูลเธรดโดยอัตโนมัติ โดยกระจายการดำเนินการไปยังทรัพยากรระบบที่มีอยู่
ประเด็นสำคัญ
OperationQueue เป็นคลาสจากเฟรมเวิร์ก Foundation ที่จัดการการทำงานของออบเจ็กต์ Operation แตกต่างจาก DispatchQueue ตรงที่ OperationQueue ไม่ต้องการระบุโหมดซีเรียลหรือคอนเคอร์เรนต์อย่างชัดเจน — จำนวนการดำเนินการที่ทำงานพร้อมกันถูกควบคุมโดยคุณสมบัติ maxConcurrentOperationCount ค่า 1 ทำให้คิวเป็นแบบเรียงลำดับ ค่าอื่นใดทำให้เป็นแบบคอนเคอร์เรนต์
Operation เป็นคลาสนามธรรมที่แสดงถึงหน่วยการทำงาน แต่ละการดำเนินการมีสถานะ: ready, executing, finished หรือ cancelled สถานะเหล่านี้เข้ากันได้กับ KVO (การสังเกตค่าคีย์) ซึ่งช่วยให้ตอบสนองต่อการเปลี่ยนแปลงได้ — ตัวอย่างเช่น อัปเดตอินเทอร์เฟซเมื่อการดำเนินการเสร็จสิ้น Operation จัดการแฟล็ก isExecuting และ isFinished โดยอัตโนมัติ
ตามข้อมูลของ Apple (2026) OperationQueue ใช้ GCD ภายในแต่เพิ่มฟังก์ชันการทำงานที่ไม่มีใน DispatchQueue: การพึ่งพา ลำดับความสำคัญ และ การยกเลิก การดำเนินการ หากแอปพลิเคชันเข้าสู่พื้นหลัง OperationQueue จะหยุดการทำงานชั่วคราวและเริ่มใหม่เมื่อกลับมา OperationQueue ยังพิจารณาจำนวนคอร์ของ CPU โดยอัตโนมัติและเลือกจำนวนเธรดที่เหมาะสมที่สุด
แต่ละการดำเนินการผ่านสี่สถานะ: pending (รอดำเนินการ), ready (พร้อม), executing (กำลังดำเนินการ) และ finished (เสร็จสิ้น) สถานะ cancelled สามารถเกิดขึ้นได้ในทุกระยะก่อนเสร็จสิ้น การเปลี่ยนสถานะจะถูกติดตามผ่าน KVO — นี่คือพื้นฐานสำหรับการอัปเดตอินเทอร์เฟซแบบรีแอกทีฟ OperationQueue จะลบการดำเนินการที่เสร็จสมบูรณ์ออกจากคิวโดยอัตโนมัติและแจ้งให้การดำเนินการที่พึ่งพาทราบว่าเงื่อนไขเบื้องต้นสำเร็จแล้ว เพื่อเริ่มการทำงาน
Operation เป็นคลาสนามธรรมที่ต้องการการแทนที่เมธอด main() หรือ start() โค้ดงานถูกวางในเมธอด main() และสถานะ isExecuting และ isFinished จะถูกจัดการโดยอัตโนมัติ สำหรับการดำเนินการแบบอะซิงโครนัส จำเป็นต้องแทนที่ start() และจัดการแฟล็กสถานะด้วยตนเอง
BlockOperation เป็นการใช้งาน Operation แบบรูปธรรมที่ทำงานบล็อกโค้ดหนึ่งบล็อกหรือมากกว่า BlockOperation จะกลายเป็นคอนเคอร์เรนต์หากคุณเพิ่มหลายบล็อกผ่าน addExecutionBlock() การดำเนินการจะเสร็จสมบูรณ์หลังจากบล็อกที่เพิ่มทั้งหมดทำงานเสร็จเท่านั้น BlockOperation เป็นทางเลือกที่สะดวกสำหรับงานง่าย ๆ โดยไม่ต้องสืบทอด
| ลักษณะ | Operation | BlockOperation |
|---|---|---|
| ประเภทคลาส | นามธรรม | รูปธรรม |
| การสืบทอด | จำเป็น | ไม่จำเป็น |
| อะซิงโครนัส | จัดการ KVO ด้วยตนเอง | อัตโนมัติ |
| บล็อกโค้ด | หนึ่งใน main() | หนึ่งหรือมากกว่า |
| การใช้งาน | งานซับซ้อนที่มีสถานะ | งานง่ายครั้งเดียว |
| เหมาะสำหรับ | การพึ่งพา การยกเลิก ความคืบหน้า | บล็อกด่วน การเสร็จสิ้น |
| หน่วยความจำ | สูงกว่าเนื่องจาก KVO และสถานะ | น้อยที่สุด เบา |
เพื่อสร้างการดำเนินการแบบกำหนดเอง ให้สืบทอดจาก Operation และแทนที่ main() ภายใน ให้ตรวจสอบแฟล็ก isCancelled ก่อนการดำเนินการที่มีต้นทุนสูงเพื่อให้แน่ใจว่าสามารถยกเลิกได้อย่างรวดเร็ว ซึ่งสำคัญสำหรับการดาวน์โหลดไฟล์ขนาดใหญ่หรือการประมวลผลข้อมูลเป็นชุด การเลือกระหว่าง Operation และ BlockOperation ขึ้นอยู่กับความซับซ้อนของงาน: สำหรับการกระทำง่ายครั้งเดียว BlockOperation ก็เพียงพอ สำหรับตรรกะที่ใช้ซ้ำได้พร้อมสถานะ ให้สืบทอดจาก Operation
การพึ่งพา เป็นข้อได้เปรียบหลักของ OperationQueue เหนือ DispatchQueue เมธอด addDependency(_:) ระบุว่าการดำเนินการ B จะทำงานหลังจากที่การดำเนินการ A เสร็จสมบูรณ์เท่านั้น การพึ่งพาสร้างกราฟแบบมีทิศทางไม่มีวงจร (DAG): หากเพิ่มการพึ่งพาแบบวงจร คิวจะละเว้นและการดำเนินการจะไม่เริ่มทำงาน
ลำดับความสำคัญ ของการดำเนินการถูกกำหนดผ่านคุณสมบัติ queuePriority ด้วยค่า: .veryLow, .low, .normal, .high, .veryHigh ลำดับความสำคัญมีผลต่อลำดับการเริ่มต้นระหว่างการดำเนินการที่พร้อม แต่ไม่แทนที่การพึ่งพา OperationQueue จะแก้ไขการพึ่งพาก่อน จากนั้นจึงใช้ลำดับความสำคัญระหว่างการดำเนินการที่มีอยู่
สถานการณ์ทั่วไป — การโหลดข้อมูลโปรไฟล์: โหลดผู้ใช้ก่อน จากนั้นตาม id ของเขาโหลดเพื่อนและโพสต์ การตั้งค่าการพึ่งพาระหว่าง การโหลดผู้ใช้ และ การโหลดเพื่อน รับประกันลำดับที่ถูกต้องโดยไม่ต้องมีตัวจัดการการเสร็จสิ้นที่ซ้อนกัน
คุณสมบัติ maxConcurrentOperationCount จำกัดจำนวนการดำเนินการที่ทำงานพร้อมกัน ค่า 1 สร้างคิวแบบเรียงลำดับ ค่าเริ่มต้น (NSOperationQueueDefaultMaxConcurrentOperationCount) เหมาะสมที่สุดสำหรับระบบและขึ้นอยู่กับโหลดปัจจุบันของอุปกรณ์ การกำหนดค่าพารามิเตอร์นี้อย่างเหมาะสม ป้องกันการใช้ทรัพยากรมากเกินไป: สำหรับการโหลดภาพ 4–6 การดำเนินการแบบขนานก็เพียงพอ สำหรับงานที่ใช้ CPU มาก ให้ใช้จำนวนคอร์ของโปรเซสเซอร์
การเลือกระหว่าง OperationQueue และ DispatchQueue ขึ้นอยู่กับ ความซับซ้อนของงาน DispatchQueue เป็นเครื่องมือน้ำหนักเบาสำหรับการเรียกอะซิงโครนัสอย่างง่าย OperationQueue เป็นโซลูชันที่หนักกว่าสำหรับสถานการณ์ที่ซับซ้อนที่มีงานที่เกี่ยวข้องกันจำนวนมาก Apple แนะนำให้เริ่มด้วย DispatchQueue และเปลี่ยนไปใช้ OperationQueue เฉพาะเมื่อต้องการการพึ่งพาหรือการยกเลิก สำหรับโครงการ iOS ส่วนใหญ่ การรวมกันของทั้งสองเครื่องมือให้ความสมดุลที่เหมาะสมระหว่างประสิทธิภาพและความยืดหยุ่น
ตามข้อมูลของ Ray Wenderlich (2025) ในโครงการ iOS ขนาดใหญ่ OperationQueue ใช้สำหรับการโหลดเนื้อหาพร้อมความคืบหน้าและการยกเลิก ในขณะที่ DispatchQueue ใช้สำหรับการดำเนินการอะซิงโครนัสอื่น ๆ ทั้งหมด อัตราส่วนประมาณ 20 ต่อ 80 โดย DispatchQueue มีมากกว่า
มาดูสามตัวอย่าง: BlockOperation อย่างง่าย Operation แบบกำหนดเองพร้อม การพึ่งพา และการดำเนินการที่ยกเลิกได้สำหรับการโหลดข้อมูล
กรณีที่ง่ายที่สุด — ทำงานบล็อกบน OperationQueue และจัดการผลลัพธ์ผ่าน completionBlock ทุก Operation มีคุณสมบัติ completionBlock ในตัว ซึ่งถูกเรียกหลังจาก main() เสร็จสิ้น
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
การพึ่งพา รับประกันว่า parseOperation จะเริ่มทำงานหลังจาก downloadOperation เสร็จสมบูรณ์เท่านั้น ซึ่งช่วยลดความจำเป็นในการเรียกกลับที่ซ้อนกัน
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
แทนที่ main() ด้วยการตรวจสอบ isCancelled เป็นระยะ ซึ่งช่วยให้การดำเนินการหยุดทันทีเมื่อถูกยกเลิก โดยไม่ต้องรอให้การดำเนินการที่มีต้นทุนสูงเสร็จสิ้น
class ImageLoadOperation: Operation {
override func main() {
guard !self.isCancelled else { return }
let image = self.downloadImage()
guard !self.isCancelled else { return }
OperationQueue.main.addOperation { self.display(image) }
}
}
การยกเลิก การดำเนินการตั้งค่าแฟล็ก isCancelled เป็น true แต่ไม่ได้หยุดเมธอด main() ที่กำลังทำงาน โค้ดภายใน main() ต้องตรวจสอบ isCancelled ด้วยตัวเองและยุติเมื่อจำเป็น นี่คือการตัดสินใจทางสถาปัตยกรรมของ Apple — ที่ช่วยให้นักพัฒนาปล่อยทรัพยากรอย่างถูกต้องเมื่อยกเลิก
การสังเกต KVO ของคุณสมบัติ isFinished และ isExecuting ช่วยให้ตอบสนองต่อการเสร็จสิ้นของการดำเนินการโดยไม่ต้องมีการเรียกกลับอย่างชัดเจน OperationQueue จะลบการดำเนินการที่เสร็จสมบูรณ์ออกจากคิวโดยอัตโนมัติ แต่การดำเนินการเหล่านั้นยังคงอยู่ในหน่วยความจำตราบเท่าที่ยังมีการอ้างอิงที่แข็งแกร่งถึงมัน KVO เป็นพื้นฐานสำหรับการผสานรวม OperationQueue กับเฟรมเวิร์กแบบรีแอกทีฟเช่น RxSwift หรือ Combine
การสมัครรับ isCancelled ผ่าน KVO ช่วยให้อัปเดตอินเทอร์เฟซเมื่อยกเลิกการดำเนินการ — ตัวอย่างเช่น แสดงตัวยึดตำแหน่งแทนการดาวน์โหลดที่ถูกยกเลิก คุณสมบัติ isCancelled เข้ากันได้กับ KVO ทำให้สะดวกสำหรับไปป์ไลน์แบบรีแอกทีฟ
อย่าสร้างการดำเนินการจำนวนมาก — แต่ละ Operation เป็นออบเจ็กต์แยกต่างหากในหน่วยความจำ หากงานสั้นและไม่ต้องการการพึ่งพา ให้ใช้ DispatchQueue โดยตรง OperationQueue เหมาะสมสำหรับสถานการณ์ที่ซับซ้อนที่มีการพึ่งพาอย่างชัดเจน การยกเลิก และการติดตามความคืบหน้า
ตรวจสอบ isCancelled ก่อนการดำเนินการที่มีต้นทุนสูง ภายในเมธอด main() ในกรณีของการดาวน์โหลดไฟล์หรือการประมวลผลภาพ การตรวจสอบหลังจากแต่ละขั้นตอนสำคัญช่วยให้ตอบสนองต่อการยกเลิกได้อย่างรวดเร็ว ใช้ if isCancelled { return } ที่จุดเริ่มต้นของ main() และหลังแต่ละการดำเนินการหลัก
จัดการ completionBlock อย่างถูกต้อง คุณสมบัติ completionBlock ของการดำเนินการถูกเรียกหลังจาก main() เสร็จสิ้น แม้ว่าการดำเนินการจะถูกยกเลิก ตรวจสอบ isCancelled ภายใน completionBlock เพื่อหลีกเลี่ยงการอัปเดตอินเทอร์เฟซด้วยข้อมูลที่ผิดพลาด OperationQueue.main เป็นคิวที่ปลอดภัยต่อเธรดสำหรับการดำเนินการอินเทอร์เฟซ คล้ายกับ DispatchQueue.main
หลีกเลี่ยงการพึ่งพาแบบวงจร — ทำให้ไม่มีการดำเนินการใดในวงจรเริ่มทำงาน OperationQueue ไม่ตรวจจับวงจรโดยอัตโนมัติ: ถ้า A พึ่งพา B และ B พึ่งพา A ทั้งคู่จะอยู่ในสถานะ ready ตลอดไป วางแผนกราฟการพึ่งพาล่วงหน้า
คำถามที่พบบ่อย
OperationQueue สร้างขึ้นบน GCD และเพิ่มการพึ่งพา ลำดับความสำคัญ KVO และการยกเลิกการดำเนินการ DispatchQueue เป็นเครื่องมือที่เบากว่าสำหรับงานอะซิงโครนัสอย่างง่ายโดยไม่มีความสามารถเหล่านี้
ตั้งค่าคุณสมบัติ maxConcurrentOperationCount เป็น 1 ซึ่งจะเปลี่ยน OperationQueue ให้เป็นคิวแบบเรียงลำดับในขณะที่คงข้อดีทั้งหมด — การพึ่งพา ลำดับความสำคัญ และการยกเลิก
เมธอด cancel() ตั้งค่าแฟล็ก isCancelled แต่ไม่ได้หยุดเมธอด main() ที่กำลังทำงาน โค้ดการดำเนินการต้องตรวจสอบ isCancelled ด้วยตัวเองและยุติ การยกเลิกทำงานเฉพาะกับการดำเนินการที่รอดำเนินการและพร้อมเท่านั้น
คุณควรสืบทอดจาก Operation เมื่อต้องการ การจัดการสถานะ อะซิงโครนัส หรือการนำตรรกะกลับมาใช้ใหม่ BlockOperation เหมาะสำหรับงานง่ายครั้งเดียวโดยไม่ต้องสืบทอด
ไม่ เว้นแต่คุณจะเรียก waitUntilFinished ด้วยพารามิเตอร์ true บนเธรดหลัก การดำเนินการทำงานบนเธรดพื้นหลังโดยค่าเริ่มต้น และผลลัพธ์จะถูกส่งกลับผ่าน OperationQueue.main
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม