ความเห็นพ้องต้องกันใน Swift พร้อมการแยกข้อกังวล

การดำเนินการใน Swift เป็นวิธีที่มีประสิทธิภาพในการแยกความรับผิดชอบออกจากคลาสต่างๆ ขณะเดียวกันก็ติดตามความคืบหน้าและการพึ่งพา มีชื่ออย่างเป็นทางการว่า NSOperations และใช้ร่วมกับ OperationQueue

ก่อนอื่นอย่าลืมอ่านบทความของฉันเกี่ยวกับ "การทำงานพร้อมกันใน Swift" เพื่อให้คุณทราบพื้นฐานของคิวและการจัดส่ง การดำเนินงานมีหลายอย่างเหมือนกันกับบล็อกการจัดส่ง แต่มีข้อดีมากกว่าสองสามประการ มาดำดิ่งกัน!

การดำเนินการใน Swift คืออะไร?

โดยทั่วไปการดำเนินการจะรับผิดชอบต่องานซิงโครนัสเดียว มันเป็นคลาสนามธรรมและไม่เคยใช้โดยตรง คุณสามารถใช้คลาสย่อย BlockOperation ที่ระบบกำหนดหรือสร้างคลาสย่อยของคุณเองได้ คุณสามารถเริ่มต้นการดำเนินการได้โดยการเพิ่มลงใน OperationQueue หรือโดยการเรียกเมธอด start ด้วยตนเอง อย่างไรก็ตาม ขอแนะนำอย่างยิ่งให้มอบความรับผิดชอบอย่างเต็มที่ให้กับ OperationQueue ในการจัดการรัฐ

การใช้ BlockOperation ที่ระบบกำหนดมีลักษณะดังนี้:

let blockOperation = BlockOperation {
    print("Executing!")
}

let queue = OperationQueue()
queue.addOperation(blockOperation)

ซึ่งสามารถทำได้โดยการเพิ่มบล็อกลงในคิวโดยตรง:

queue.addOperation {
  print("Executing!")
}

งานที่กำหนดจะถูกเพิ่มใน OperationQueue ซึ่งจะเริ่มดำเนินการโดยเร็วที่สุด

การสร้างการดำเนินการแบบกำหนดเอง

คุณสร้างการแยกข้อกังวลด้วยการดำเนินการแบบกำหนดเอง ตัวอย่างเช่น คุณสามารถสร้างการใช้งานที่กำหนดเองสำหรับการนำเข้าเนื้อหา และอีกวิธีหนึ่งสำหรับการอัปโหลดเนื้อหา

ตัวอย่างโค้ดต่อไปนี้แสดงคลาสย่อยที่กำหนดเองสำหรับการนำเข้าเนื้อหา:

final class ContentImportOperation: Operation {

    let itemProvider: NSItemProvider

    init(itemProvider: NSItemProvider) {
        self.itemProvider = itemProvider
        super.init()
    }

    override func main() {
        guard !isCancelled else { return }
        print("Importing content..")
        
        // .. import the content using the item provider

    }
}

ชั้นเรียนรับผู้ให้บริการรายการและนำเข้าเนื้อหาภายในวิธีการหลัก ฟังก์ชัน main() เป็นวิธีเดียวที่คุณต้องเขียนทับสำหรับการดำเนินการแบบซิงโครนัส เพิ่มการดำเนินการลงในคิว และตั้งค่าบล็อคการดำเนินการให้เสร็จสิ้นเพื่อติดตามความสำเร็จ:

let fileURL = URL(fileURLWithPath: "..")
let contentImportOperation = ContentImportOperation(itemProvider: NSItemProvider(contentsOf: fileURL)!)

contentImportOperation.completionBlock = {
    print("Importing completed!")
}

queue.addOperation(contentImportOperation)

// Prints:
// Importing content..
// Importing completed!

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

สถานะต่าง ๆ ของการดำเนินการ

การดำเนินการสามารถมีได้หลายสถานะ ขึ้นอยู่กับสถานะการดำเนินการในปัจจุบัน

  • พร้อม:พร้อมแล้วที่จะเริ่ม
  • กำลังดำเนินการ:งานกำลังทำงานอยู่
  • เสร็จสิ้น:เมื่อกระบวนการเสร็จสิ้น
  • ยกเลิกแล้ว:งานถูกยกเลิก

สิ่งสำคัญคือต้องรู้ว่าการดำเนินการสามารถดำเนินการได้เพียงครั้งเดียวเท่านั้น เมื่อใดก็ตามที่อยู่ในสถานะเสร็จสิ้นหรือยกเลิก คุณจะไม่สามารถรีสตาร์ทอินสแตนซ์เดิมได้อีกต่อไป

ภายในการใช้งานแบบกำหนดเอง คุณต้องตรวจสอบสถานะที่ถูกยกเลิกด้วยตนเองก่อนดำเนินการเพื่อให้แน่ใจว่างานจะถูกยกเลิก โปรดทราบว่าการแข่งขันของข้อมูลสามารถเกิดขึ้นเมื่อการดำเนินการเริ่มต้นและยกเลิกพร้อมกัน คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการแข่งขันของข้อมูลได้ในบล็อกโพสต์ของฉัน “Thread Sanitizer อธิบาย: Data Races in Swift

OperationQueue จะลบงานออกจากคิวโดยอัตโนมัติเมื่อเสร็จสิ้น ซึ่งเกิดขึ้นทั้งหลังการดำเนินการหรือหลังการยกเลิก

การใช้การพึ่งพาอาศัยกัน

ประโยชน์ของการใช้การดำเนินการคือการใช้การพึ่งพา คุณสามารถเพิ่มการพึ่งพาระหว่างสองอินสแตนซ์ได้อย่างง่ายดาย ตัวอย่างเช่น หากต้องการเริ่มอัปโหลดหลังจากนำเข้าเนื้อหาแล้ว:

let fileURL = URL(fileURLWithPath: "..")
let contentImportOperation = ContentImportOperation(itemProvider: NSItemProvider(contentsOf: fileURL)!)
contentImportOperation.completionBlock = {
    print("Importing completed!")
}

let contentUploadOperation = UploadContentOperation()
contentUploadOperation.addDependency(contentImportOperation)
contentUploadOperation.completionBlock = {
    print("Uploading completed!")
}

queue.addOperations([contentImportOperation, contentUploadOperation], waitUntilFinished: true)

// Prints:
// Importing content..
// Uploading content..
// Importing completed!
// Uploading completed!

การอัปโหลดจะเริ่มหลังจากการนำเข้าเนื้อหาเสร็จสิ้นแล้วเท่านั้น ไม่คำนึงถึงการยกเลิก ซึ่งหมายความว่าหากการดำเนินการนำเข้ายกเลิก การอัปโหลดก็จะยังเริ่มต้นอยู่

คุณต้องดำเนินการตรวจสอบเพื่อดูว่าการอ้างอิงถูกยกเลิกหรือไม่:

final class UploadContentOperation: Operation {
    override func main() {
        guard !dependencies.contains(where: { $0.isCancelled }), !isCancelled else {
            return
        }

        print("Uploading content..")
    }
}

บทสรุป

ฉันหวังว่าคุณจะตื่นเต้นที่จะเริ่มดำเนินการใน Swift เป็นอัญมณีที่ซ่อนอยู่ซึ่งช่วยให้คุณสามารถแยกข้อกังวล เพิ่มการพึ่งพาระหว่างงาน และติดตามความสำเร็จได้