受WWDC 2015高级NSOPERATIONS会议启发的Swift框架。以前称为运营,由@Danthorpe开发,并在我们出色的社区提供了很多帮助下。
| 资源 | 在哪里找到它 |
|---|---|
| 会话视频 | developer.apple.com |
| 旧但更完整的参考文档 | docs.danthorpe.me/operations |
| 更新但尚未完整的参考文档 | procepure.kit.run/development |
| 编程指南 | operations.readme.io |
ProcedureKit支持所有当前的Apple平台。最低要求是:
ProcedureKit(5.1.0)的当前发布版本支持Swift 4.2+和Xcode 10.1。 development分支是Swift 5和Xcode 10.2兼容。
ProcedureKit是一个“多模块”框架(不要打扰谷歌搜索,我只是编造了)。我的意思是,Xcode项目具有多个目标/产品,每个目标/产品都会产生快速模块。这些模块中的一些是跨平台,其他模块是专用的,例如ProcedureKitNetwork vs ProcedureKitMobile 。
请参阅《安装过程指南》。
Procedure是一个Foundation.Operation子类。这是必须分类的抽象类。
import ProcedureKit
class MyFirstProcedure : Procedure {
override func execute ( ) {
print ( " Hello World " )
finish ( )
}
}
let queue = ProcedureQueue ( )
let myProcedure = MyFirstProcedure ( )
queue . add ( procedure : myProcedure )这里的要点是:
Procedureexecute但不要致电super.execute()finish() 。这可以异步完成。ProcedureQueue的实例中。 观察者附在Procedure子类上。当生命周期事件发生时,他们会收到回调。生命周期事件是:确实附加,将执行,执行,确实取消,将添加新操作,添加新操作,将完成并完成。
这些方法是由协议定义的,因此可以编写自定义类以符合多个事件。但是,存在基于块的方法可以更自然地添加观察者。例如,观察何时完成过程:
myProcedure . addDidFinishBlockObserver { procedure , errors in
procedure . log . info ( message : " Yay! Finished! " )
}该框架还提供了BackgroundObserver , TimeoutObserver和NetworkObserver 。
有关更多信息,请参见[[观察者|观察者]]上的Wiki。
条件附在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中)。
请参阅[[条件|条件]]或条件上的旧编程指南|有关更多信息。
功能代表了应用程序访问设备或用户帐户能力的能力,或者可能是任何类型的门控资源。例如,位置服务,云套件容器,日历等或网络服务。 CapabiltiyProtocol提供了一个统一模型:
GetAuthorizationStatusProcedure检查当前的授权状态,AuthorizeCapabilityProcedureAuthorizedFor条件。例如:
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相关的类型,这是待处理结果类型。
将其整合在一起的是一组API, 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 )好吧,那刚刚发生了什么?好吧, injectResult API具有一个可以接受尾随封闭的变体。闭合接收输出值,并且必须返回输入值(或投掷错误)。因此, { $0.speed }将从用户的CLLocation实例返回速度属性。
这里要注意的关键是,此闭合可以同步运行。因此,最好不要把任何繁重的东西放在上面。如果您需要进行更复杂的数据映射,请查看TransformProcedure和AsyncTransformProcedure 。
有关更多信息,请参见注射结果的编程指南。