เฟรมเวิร์ก Swift ที่ได้รับแรงบันดาลใจจาก WWDC 2015 ขั้นสูงเซสชัน NSOperations ขั้นสูง ก่อนหน้านี้รู้จักกันในชื่อ การดำเนินงาน พัฒนาโดย @danthorpe ด้วยความช่วยเหลือมากมายจากชุมชนที่ยอดเยี่ยมของเรา
| ทรัพยากร | จะหาได้ที่ไหน |
|---|---|
| วิดีโอเซสชัน | Developer.apple.com |
| เอกสารอ้างอิงเก่า แต่สมบูรณ์ยิ่งขึ้น | docs.danthorpe.me/operations |
| อัปเดต แต่ยังไม่สมบูรณ์เอกสารเอกสาร | procedure.kit.run/development |
| คู่มือการเขียนโปรแกรม | การดำเนินการ readme.io |
PROCEDUREKIT รองรับแพลตฟอร์ม Apple ปัจจุบันทั้งหมด ข้อกำหนดขั้นต่ำคือ:
เวอร์ชันปัจจุบันของ ProcedureKit (5.1.0) รองรับ Swift 4.2+ และ XCode 10.1 สาขา development เป็น Swift 5 และ Xcode 10.2 เข้ากันได้
ProcedureKit เป็นเฟรมเวิร์ก "หลายโมดูล" (อย่ารบกวน googling ที่ฉันเพิ่งทำขึ้นมา) สิ่งที่ฉันหมายถึงคือโครงการ XCode มีเป้าหมาย/ผลิตภัณฑ์หลายรายการซึ่งแต่ละรายการสร้างโมดูล Swift โมดูลเหล่านี้บางส่วนเป็นข้ามแพลตฟอร์มอื่น ๆ มีการทุ่มเทเช่น ProcedureKitNetwork vs ProcedureKitMobile
ดูคู่มือการติดตั้งขั้นตอนการติดตั้ง
Procedure เป็น subclass Foundation.Operation มันเป็นคลาสนามธรรมซึ่ง จะต้อง เป็นคลาสย่อย
import ProcedureKit
class MyFirstProcedure : Procedure {
override func execute ( ) {
print ( " Hello World " )
finish ( )
}
}
let queue = ProcedureQueue ( )
let myProcedure = MyFirstProcedure ( )
queue . add ( procedure : myProcedure )ประเด็นสำคัญที่นี่คือ:
Procedure ตอนย่อยexecute แต่อย่าโทร super.execute()finish() เสมอหลังจาก ทำงาน เสร็จหรือหากขั้นตอนถูกยกเลิก สิ่งนี้สามารถทำได้แบบอะซิงโครนัสProcedureQueue ผู้สังเกตการณ์ติดอยู่กับ Procedure ขั้นตอน พวกเขาได้รับการโทรกลับเมื่อเหตุการณ์วงจรชีวิตเกิดขึ้น เหตุการณ์วงจรชีวิตคือ: ไม่แนบ จะดำเนินการ , ดำเนิน การ, ยกเลิก , จะเพิ่มการดำเนินการใหม่ , เพิ่มการดำเนินการใหม่ , จะเสร็จสิ้น และ เสร็จสิ้น
วิธีการเหล่านี้ถูกกำหนดโดยโปรโตคอลดังนั้นคลาสที่กำหนดเองสามารถเขียนเพื่อให้สอดคล้องกับหลายเหตุการณ์ อย่างไรก็ตามมีวิธีการตามบล็อกเพื่อเพิ่มผู้สังเกตการณ์ตามธรรมชาติมากขึ้น ตัวอย่างเช่นการสังเกตเมื่อขั้นตอนเสร็จสิ้น:
myProcedure . addDidFinishBlockObserver { procedure , errors in
procedure . log . info ( message : " Yay! Finished! " )
} เฟรมเวิร์กยังให้ BackgroundObserver , TimeoutObserver และ NetworkObserver
ดูวิกิบน [[ผู้สังเกตการณ์ | ผู้สังเกตการณ์]] สำหรับข้อมูลเพิ่มเติม
เงื่อนไขถูกแนบกับ Procedure ขั้นตอน ก่อนที่ขั้นตอนจะพร้อมที่จะดำเนินการมันจะ ประเมิน เงื่อนไขทั้งหมดแบบอะซิงโครนัส หากเงื่อนไขใด ๆ ล้มเหลวมันจะเสร็จสิ้นด้วยข้อผิดพลาดแทนที่จะดำเนินการ ตัวอย่างเช่น:
myProcedure . add ( condition : BlockCondition {
// procedure will execute if true
// procedure will be ignored if false
// procedure will fail if error is thrown
return trueOrFalse // or throw AnError()
}เงื่อนไขสามารถร่วมกันได้ นี่เป็นสิ่งที่คล้ายกับการล็อคที่ถูกจัดขึ้นเพื่อป้องกันการดำเนินการอื่น ๆ ที่มีการยกเว้นแบบเดียวกัน
เฟรมเวิร์กให้เงื่อนไขดังต่อไปนี้: AuthorizedFor , BlockCondition , MutuallyExclusive , NegatedCondition , NoFailedDependenciesCondition , SilentCondition และ UserConfirmationCondition (ใน ProcedureKitMobile )
ดู wiki บน [[เงื่อนไข | เงื่อนไข]] หรือคู่มือการเขียนโปรแกรมเก่าเกี่ยวกับเงื่อนไข | สำหรับข้อมูลเพิ่มเติม
ความสามารถ แสดงถึงความสามารถของแอปพลิเคชันในการเข้าถึงอุปกรณ์หรือความสามารถของบัญชีผู้ใช้หรืออาจมีทรัพยากรที่มีรั้วรอบขอบชิดทุกประเภท ตัวอย่างเช่นบริการสถานที่, คอนเทนเนอร์คลาวด์, ปฏิทิน ฯลฯ หรือเว็บไซต์ CapabiltiyProtocol ให้แบบจำลองแบบรวมเป็น:
GetAuthorizationStatusProcedureAuthorizeCapabilityProcedureAuthorizedForตัวอย่างเช่น:
import ProcedureKit
import ProcedureKitLocation
class DoSomethingWithLocation : Procedure {
override init ( ) {
super . init ( )
name = " Location Operation "
add ( condition : AuthorizedFor ( Capability . Location ( . whenInUse ) ) )
}
override func execute ( ) {
// do something with Location Services here
finish ( )
}
} ProcedureKit ให้ความสามารถดังต่อไปนี้: Capability.CloudKit และ Capability.Location
ใน การดำเนินงาน (เวอร์ชันก่อนหน้าของเฟรมเวิร์กนี้) มีฟังก์ชั่นการใช้งานมากขึ้น (ปฏิทินสุขภาพภาพถ่ายสมุดที่อยู่ ฯลฯ ) และเรายังคงพิจารณาวิธีการเสนอสิ่งเหล่านี้ใน ProcedureKit
ดูวิกิบน [[ความสามารถ | ความสามารถ]] หรือคู่มือการเขียนโปรแกรมเก่าเกี่ยวกับความสามารถสำหรับข้อมูลเพิ่มเติม
Procedure มีฟังก์ชั่นการบันทึกภายในของตัวเองที่เปิดเผยผ่านคุณสมบัติ log :
class LogExample : Procedure {
override func execute ( ) {
log . info ( " Hello World! " )
finish ( )
}
}ดูคู่มือการเขียนโปรแกรมสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการบันทึกและสนับสนุนกรอบบันทึกของบุคคลที่สาม
บ่อยครั้งที่ขั้นตอนจะต้องมีการพึ่งพาเพื่อดำเนินการ ตามปกติกับแอปพลิเคชันแบบอะซิงโครนัส/เหตุการณ์การพึ่งพาเหล่านี้อาจไม่เป็นที่รู้จักในเวลาสร้าง แต่จะต้องถูกฉีดหลังจากขั้นตอนเริ่มต้น แต่ก่อนที่จะดำเนินการ ProcedureKit รองรับสิ่งนี้ผ่านชุดของโปรโตคอลและประเภทที่ทำงานร่วมกัน เราคิดว่ารูปแบบนี้ยอดเยี่ยมมากเพราะมันส่งเสริมองค์ประกอบของขั้นตอนการวัตถุประสงค์เดียวขนาดเล็ก สิ่งเหล่านี้สามารถทดสอบได้ง่ายขึ้นและอาจเปิดใช้งานการใช้ซ้ำได้มากขึ้น คุณจะพบกับการฉีดพึ่งพาการใช้และสนับสนุนตลอดกรอบนี้
อย่างไรก็ตามประการแรกค่าอาจพร้อมหรือรอดำเนินการ ตัวอย่างเช่นเมื่อขั้นตอนมีการกำหนดค่าเริ่มต้นมันอาจไม่มีการพึ่งพาทั้งหมดดังนั้นพวกเขาจึงอยู่ในสถานะที่รอดำเนินการ หวังว่าพวกเขาจะพร้อมตามเวลาที่มันดำเนินการ
ประการที่สองหากขั้นตอนได้รับการพึ่งพาการพึ่งพาตามขั้นตอนอื่นอาจประสบความสำเร็จหรืออาจล้มเหลวด้วยข้อผิดพลาด ดังนั้นจึงมีประเภท ผลลัพธ์ ง่าย ๆ ที่รองรับสิ่งนี้
ประการที่สามมีโปรโตคอลที่จะกำหนดคุณสมบัติ input และ output
InputProcedure เชื่อมโยงประเภท Input คลาส Procedure ขั้นตอนสามารถสอดคล้องกับสิ่งนี้เพื่อให้สามารถฉีดพึ่งพาได้ โปรดทราบว่ามีเพียงคุณสมบัติ input เพียงหนึ่งเดียวเท่านั้นที่ได้รับการสนับสนุนดังนั้นสร้างประเภทโครงสร้างระดับกลางเพื่อให้มีการพึ่งพาหลายรายการ แน่นอนคุณสมบัติ input เป็นประเภทค่าที่รอดำเนินการ
OutputProcedure เปิดเผยประเภทที่เกี่ยวข้องกับ Output ผ่านคุณสมบัติ output ซึ่งเป็นประเภทผลลัพธ์ที่รอดำเนินการ
การนำมันทั้งหมดเข้าด้วยกันเป็นชุดของ APIs บน InputProcedure ซึ่งช่วยให้การพึ่งพาการผูกมัดร่วมกัน แบบนี้:
import ProcedureKitLocation
// This class is part of the framework, it
// conforms to OutputProcedure
let getLocation = UserLocationProcedure ( )
// Lets assume we've written this, it
// conforms to InputProcedure
let processLocation = ProcessUserLocation ( )
// This line sets up dependency & injection
// it automatically handles errors and cancellation
processLocation . injectResult ( from : getLocation )
// Still need to add both procedures to the queue
queue . add ( procedures : getLocation , processLocation ) ในด้านบนสันนิษฐานว่าประเภท Input ตรงกับประเภท Output ในกรณีนี้ CLLocation อย่างไรก็ตามยังเป็นไปได้ที่จะใช้การปิดเพื่อนวดประเภทเอาต์พุตไปยังประเภทอินพุตที่ต้องการเช่น:
import ProcedureKitLocation
// This class is part of the framework, it
// conforms to OutputProcedure
let getLocation = UserLocationProcedure ( )
// Lets assume we've written this, it
// conforms to InputProcedure, and
// requires a CLLocationSpeed value
let processSpeed = ProcessUserSpeed ( )
// This line sets up dependency & injection
// it automatically handles errors and cancellation
// and the closure extracts the speed value
processLocation . injectResult ( from : getLocation ) { $0 . speed }
// Still need to add both procedures to the queue
queue . add ( procedures : getLocation , processLocation ) โอเคแล้วเกิดอะไรขึ้น? API injectResult มีตัวแปรที่ยอมรับการปิดท้าย การปิดรับค่าเอาต์พุตและต้องส่งคืนค่าอินพุต (หรือโยนข้อผิดพลาด) ดังนั้น { $0.speed } จะส่งคืนคุณสมบัติความเร็วจากอินสแตนซ์ CLLocation ของผู้ใช้
สิ่งสำคัญที่ควรทราบที่นี่คือการปิดนี้ทำงานแบบซิงโครนัส ดังนั้นจึงเป็นการดีที่สุดที่จะไม่ใส่อะไรเลย หากคุณต้องการทำการแมปข้อมูลที่ซับซ้อนมากขึ้นให้ตรวจสอบ TransformProcedure และ AsyncTransformProcedure
ดูคู่มือการเขียนโปรแกรมเกี่ยวกับผลลัพธ์การฉีดสำหรับข้อมูลเพิ่มเติม