Waxwing
iOS version migrations in Swift. When mangling data or performing any other kind of updates you want to ensure that all relevant migrations are run in order and only once. Waxwing allows you to do just that.
Requirements
- Swift 5
- iOS 8+
Installation
Cocoapods
Waxwing is available through CocoaPods. To install add the following line to your Podfile:
pod "Waxwing"
Carthage
If you don't like CocoaPods, you can add the dependency via Carthage or include Waxwing.swift
in your project.
Swift Package Manager
You can use the Swift Package Manager to install Waxwing
by adding it to your Package.swift
file:
import PackageDescription
let package = Package(
name: "YOUR_PROJECT_NAME",
targets: [],
dependencies: [
.Package(url: "https://github.com/JanGorman/Waxwing", majorVersion: 5),
]
)
Usage
There are two ways to run your migrations, either with closures or through an OperationQueue
:
import Waxwing
…
let waxwing = Waxwing(bundle: .main, defaults: .standard)
waxwing.migrateToVersion("0.9") {
firstMigrationCall()
secondMigrationCall()
…
}
or
import Waxwing
…
let waxwing = Waxwing()
Waxwing.migrateToVersion("0.9", [FirstMigrationClass(), SecondMigrationClass()])
Note that closure based migrations are run from the thread they are created on. Anything that has to run on the main thread, such as notifying your users of changes introduced with this version, needs to explictly call the method on the main thread:
import Waxwing
DispatchQueue.global().async {
let waxwing = Waxwing(bundle: .main, defaults: .standard)
waxwing.migrateToVersion("0.9") {
DispatchQueue.main.async {
// Some alert that we're done updating / what's new in this version of the app
}
}
}
The OperationQueue
based migrations are always run from their own queue so the same caveat applies. Also note, that if any of the migrations in the queue depend on another one having run first, you explicitly need to add that dependency. Operation
makes this trivial through the addDependency()
method.
You can add as many migrations as you want. They will only ever be executed once.
Progress
Waxwing has built in support for Progress. Since the number of actions that are run using the closure based method cannot be determined it just reports a total unit count of 1. If you're using operations, the unit count will match the number of migrations.
import Waxwing
func migrate() {
let progress = Progress(totalUnitCount: 1)
progress.becomeCurrent(withPendingUnitCount: 1)
_ = progress.observe(\.fractionCompleted, options: [.new]) { progress, _ in
// e.g. Update progress indicator, remember to do this on the main thread
}
waxwing.migrateToVersion("0.8", migrations: [migration1, migration2, migration3…])
}
For more information on how Progress
works I recommend this article by Ole Begemann.
Author
Jan Gorman
License
Waxwing is available under the MIT license. See the LICENSE file for more info.