4.0.0-beta-1 (#469)
Pre-release4.0.0 Beta 1
Well, it’s time to say goodbye to Operations and hello to ProcedureKit. ProcedureKit is a complete re-write of Operations in Swift 3.0, and has the following key changes.
-
ProcedureKit
Operations has been lucky to have many contributors, and for ProcedureKit I wanted to be able to recognise the fantastic contributions of this little community properly. So the repository has been transferred into an organization. At the moment, the only additional member is @swiftlyfalling however I hope that more will join soon. In addition to moving to an org, there are now contribution guidelines and code of conduct documents. -
Naming changes
Because Swift 3.0 has dropped theNS
prefix from many classes, includingNSOperation
,NSOperationQueue
andNSBlockOperation
, Operations had some pretty significant issues in Swift 3.0. At WWDC this year, I was able to discuss Operations with Dave DeLong and Philippe Hausler. We brainstormed some alternatives, and came up with “Procedure”, which I’ve sort of grown accustomed to now. The name changes are widespread, and essentially, what was onceOperation
is nowProcedure
. -
Project structure
For a long time, we’ve had an issue where some classes are not extension API compatible. This has resulted in having two projects in the repository, which in turn leads to problems with Carthage not being able to build desired frameworks. With ProcedureKit, this problem is entirely resolved. The core framework, which is the focus of this beta, is entirely extension API compatible. It should be imported like this:import ProcedureKit
Functionality which depends on UIKit, such as
AlertProcedure
will be exposed in a framework calledProcedureKitMobile
, and imported like this:import ProcedureKit import ProcedureKitMobile
Similarly for other non-core functionality like CloudKit wrappers etc.
In addition to types which should be used in applications, I wanted to expose types to aid writing unit tests. This is called
TestingProcedureKit
, which itself links againstXCTest
. It can only be used inside test bundle targets. This framework includesProcedureKitTestCase
andStressTestCase
which are suitable for subclassing. The former then exposes simple APIs to wait for procedures to run usingXCTestExpectation
. Additionally, there areXCTAssertProcedure*
style macros which can assert that aProcedure
ran as expected. To use it in your own application’s unit test target:import ProcedureKit import TestingProcedureKit @testable import MyApplication
-
Beta 1 Functionality
This beta is focused on the minimum. It hasProcedure
,ProcedureQueue
,GroupProcedure
,MapProcedure
,BlockProcedure
andDelayProcedure
. In addition, there is support for the following features:- Attaching conditions which may support mutual exclusion
- Adding observers - see notes below.
- Result injection has been simplified to a single protocol.
- Full logging support
- Errors are consolidated into a single
ProcedureKitError
type.
-
Observers
An annoying element of the observers in Operations is that the receivedOperation
does not retain full type fidelity. It’s justOperation
, notMyOperationSubclass
. WithProcedureKit
this has been fixed as now the underlying protocolProcedureObserver
is generic over theProcedure
which is possible as there is now aProcedureProtocol
. This means, that the block observers are now generic too. Additionally, an extension onProcedureProtocol
provides convenience methods for adding block observers. This means that adding block observers should now be done like this:let foo = FooProcedure() foo.addDidFinishBlockObserver { foo, errors in // No need to cast argument to FooProcedure foo.doFooMethod() }
-
BlockProcedure
The API forBlockProcedure
has changed somewhat. The block type is now() throws -> Void
. In some regards this is a reduction in capability overBlockOperation
from Operations which received a finishing block. The finishing block meant that the block could have an asynchronous callback to it.While this functionality might return, I think that it is far better to have a simple abstraction around synchronous work which will be enqueued and can throw errors. For asynchronous work, it would be best to make a proper
Procedure
subclass.Having said that, potentially we will add
AsyncBlockProcedure
to support this use case. Please raise an issue if this is something you care about!
Anyway, I think that is about it - thanks to all the contributors who have supported Operations and ProcedureKit while this has been written. Stay tuned for Beta 2 in a week or so.