Ein schneller Rahmen, der von der WWDC 2015 Advanced NSOperations -Sitzung inspiriert wurde. Früher als Operationen bekannt, entwickelt von @Danthorpe mit viel Hilfe unserer fantastischen Community.
| Ressource | Wo man es findet |
|---|---|
| Sitzungsvideo | Entwickler.apple.com |
| Alte, aber vollständigere Referenzdokumentation | docs.danthorpe.me/operations |
| Aktualisiert, aber noch nicht vollständige Referenzdokumente | procedure.kit.run/development |
| Programmieranleitung | operations.readme.io |
Procedurekit unterstützt alle aktuellen Apple -Plattformen. Die Mindestanforderungen sind:
Die aktuelle veröffentlichte Version von ProcedureKit (5.1.0) unterstützt Swift 4.2+ und Xcode 10.1. Der development ist Swift 5 und Xcode 10.2 kompatibel.
Procedurekit ist ein "Multi-Modul" -Frahmen (ich mach dir nicht die Mühe, das zu googeln, ich habe es gerade erfunden). Was ich meine, ist, dass das Xcode -Projekt mehrere Ziele/Produkte enthält, von denen jeweils ein Swift -Modul erzeugt. Einige dieser Module sind ProcedureKitNetwork , andere sind dediziert, z ProcedureKitMobile
Siehe den Installationsprozedurekit -Handbuch.
Procedure ist eine Unterklasse Foundation.Operation . Es ist eine abstrakte Klasse, die unterklassifiziert werden muss .
import ProcedureKit
class MyFirstProcedure : Procedure {
override func execute ( ) {
print ( " Hello World " )
finish ( )
}
}
let queue = ProcedureQueue ( )
let myProcedure = MyFirstProcedure ( )
queue . add ( procedure : myProcedure )Die wichtigsten Punkte hier sind:
Procedureexecute , aber nicht super.execute()finish() nach Abschluss der Arbeiten oder wenn die Prozedur storniert wird. Dies könnte asynchron erfolgen.ProcedureQueue hinzu. Beobachter sind an eine Procedure angeschlossen. Sie erhalten Rückrufe, wenn Lebenszyklusereignisse auftreten. Die Lebenszyklusereignisse sind: Did Attach , wird ausgeführt , ausgeführt , di -storniert , wird einen neuen Betrieb hinzufügen , einen neuen Betrieb hinzufügen , erledigen und beenden .
Diese Methoden werden durch ein Protokoll definiert, sodass benutzerdefinierte Klassen so geschrieben werden können, dass sie mehreren Ereignissen entsprechen. Es gibt jedoch blockbasierte Methoden, um Beobachter natürlicher hinzuzufügen. Zum Beispiel zu beobachten, wann ein Verfahren abgeschlossen ist:
myProcedure . addDidFinishBlockObserver { procedure , errors in
procedure . log . info ( message : " Yay! Finished! " )
} Das Framework bietet auch BackgroundObserver , TimeoutObserver und NetworkObserver .
Weitere Informationen finden Sie im Wiki über [[Beobachter | Beobachter]].
Die Bedingungen werden an eine Procedure angeschlossen. Bevor ein Verfahren bereit ist, um auszuführen, bewertet es asynchron alle seine Bedingungen. Wenn eine Bedingung fehlschlägt, endet er mit einem Fehler, anstatt auszuführen. Zum Beispiel:
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()
}Die Bedingungen können sich gegenseitig ausschließen. Dies ähnelt einem Schloss, der andere Operationen verhindern wird, wobei der gleiche Ausschluss ausgeführt wird.
Das Rahmen enthält die folgenden Bedingungen: AuthorizedFor BlockCondition , MutuallyExclusive , NegatedCondition , NoFailedDependenciesCondition , SilentCondition und UserConfirmationCondition (in procedurekitmobile ).
Siehe das Wiki zu [[Bedingungen | Bedingungen]] oder den alten Programmierleitfaden zu den Bedingungen | Weitere Informationen.
Eine Fähigkeit stellt die Fähigkeit der Anwendung dar, auf Geräte- oder Benutzerkontofähigkeiten oder möglicherweise jede Art von Gated -Ressource zuzugreifen. Zum Beispiel Standortdienste, Cloud -Kit -Container, Kalender usw. oder ein Webservice. Das CapabiltiyProtocol bietet ein einheitliches Modell für:
GetAuthorizationStatusProcedure .AuthorizeCapabilityProcedure anAuthorizedFor bezeichnet wird.Zum Beispiel:
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 bietet die folgenden Funktionen: Capability.CloudKit und Capability.Location .
In den Operationen (eine frühere Version dieses Frameworks) bestand mehr Funktionalität (Kalender, Gesundheit, Fotos, Adressbuch usw.), und wir überlegen immer noch, wie diese in ProcedureKit angeboten werden können.
Weitere Informationen finden Sie im Wiki über [[Funktionen | Funktionen]] oder den alten Programmierleitfaden zu Funktionen.
Procedure hat eine eigene interne Protokollierungsfunktion, die über eine log ausgesetzt ist:
class LogExample : Procedure {
override func execute ( ) {
log . info ( " Hello World! " )
finish ( )
}
}Weitere Informationen zur Protokollierung und Unterstützung von Protokoll -Frameworks von Drittanbietern finden Sie im Programmierhandbuch.
Oft benötigen Verfahren Abhängigkeiten, um auszuführen. Wie bei asynchronen/ereignisbasierten Anwendungen typisch ist, sind diese Abhängigkeiten möglicherweise nicht zur Erstellungszeit bekannt. Stattdessen müssen sie nach dem Initialisierungsverfahren injiziert werden, aber bevor es ausgeführt wird. Procedurekit unterstützt dies über eine Reihe von Protokollen und Typen, die zusammenarbeiten. Wir denken, dass dieses Muster großartig ist, da es die Zusammensetzung kleiner einzelner Zweckverfahren fördert. Diese können einfacher zu testen sein und möglicherweise eine größere Wiederverwendung ermöglichen. In diesem Rahmen wird die Abhängigkeitsinjektion verwendet und gefördert.
Erstens kann ein Wert bereit oder ausstehend sein. Wenn beispielsweise ein Verfahren initialisiert wird, hat es möglicherweise nicht alle Abhängigkeiten, sodass sie sich in einem ausstehenden Zustand befinden. Hoffentlich werden sie bereit, wenn sie ausgeführt werden.
Zweitens kann ein Verfahren die Abhängigkeit erfasst, die durch ein anderes Verfahren erforderlich ist, oder kann es mit einem Fehler fehlschlagen. Daher gibt es einen einfachen Ergebnistyp , der dies unterstützt.
Drittens gibt es Protokolle, um die input und output zu definieren.
InputProcedure assoziiert einen Input . Eine Procedure kann diesem entsprechen, um die Abhängigkeitsinjektion zu ermöglichen. Beachten Sie, dass nur eine input unterstützt wird, und erstellen daher Zwischenstrukturarten, die mehrere Abhängigkeiten enthalten. Natürlich ist die input ein ausstehender Werttyp.
OutputProcedure enthält den zugeordneten Output über seine output , die ein ausstehender Ergebnistyp ist.
Alles zusammenzubringen ist eine Reihe von APIs für InputProcedure , die es zusammenketten. So was:
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 ) Im obigen oben wird angenommen, dass der Input in diesem Fall die CLLocation mit dem Output übereinstimmte. Es ist jedoch auch möglich, einen Verschluss zu verwenden, um den Ausgangstyp zum erforderlichen Eingangstyp zu massieren, beispielsweise:
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 ) Okay, was ist gerade passiert? Nun, die injectResult -API hat eine Variante, die einen nachfolgenden Verschluss akzeptiert. Der Verschluss empfängt den Ausgabewert und muss den Eingangswert zurückgeben (oder einen Fehler werfen). Also gibt { $0.speed } die Speed -Eigenschaft aus der CLLocation -Instanz des Benutzers zurück.
Die wichtige Sache, die hier zu beachten ist, ist, dass dieser Verschluss synchron ausgeführt wird. Es ist also am besten, nichts Beunruhigendes darauf zu legen. Wenn Sie komplexere Datenzuordnungen durchführen müssen, lesen Sie TransformProcedure und AsyncTransformProcedure .
Weitere Informationen finden Sie im Programmierhandbuch zum Injektieren von Ergebnissen.