Swiftpack.co - FabrizioBrancati/Queuer as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by FabrizioBrancati.
FabrizioBrancati/Queuer 3.0.0
Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).
⭐️ 1,048
🕓 7 hours ago
iOS macOS watchOS tvOS macCatalyst
.package(url: "https://github.com/FabrizioBrancati/Queuer.git", from: "3.0.0")

Queuer

GitHub Release Swift Versions Swift Platforms

Features

Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD). It allows you to create any asynchronous and synchronous task easily, all managed by a queue, with just a few lines.

Here is the list of all the features:

  • ☑ Works on all Swift compatible platforms (even Linux)
  • ☑ Easy to use
  • ☑ Well documented (100% documented)
  • ☑ Well tested (100% of code coverage)
  • ☑ Create an operation block
  • ☑ Create a single operation
  • ☑ Create chained operations
  • ☑ Manage a centralized queue
  • ☑ Create unlimited queue
  • ☑ Declare how many concurrent operation a queue can handle
  • ☑ Create semaphores
  • ☑ Create and handle schedules
  • ☑ Automatically or manually retry an operation
  • ☐ Throttling between each automatic operation retry

Requirements

Swift Queuer iOS macOS macCatalyst tvOS watchOS visionOS Linux
3.1...3.2 1.0.0...1.1.0 8.0+ 10.10+ 9.0+ 2.0+
4.0 1.3.0 8.0+ 10.10+ 9.0+ 2.0+
4.1 1.3.1...1.3.2 8.0+ 10.10+ 9.0+ 2.0+
4.2 2.0.0...2.0.1 8.0+ 10.10+ 9.0+ 3.0+
5.0...5.10 2.1.0...2.2.0 8.0+ 10.10+ 9.0+ 3.0+
5.9...5.10 3.0.0 12.0+ 10.13+ 13.0+ 12.0+ 4.0+ 1.0+

Installing

See Requirements section to check Swift, Queuer, and OS versions.

In your Package.swift Swift Package Manager manifest, add the following dependency to your dependencies argument:

.package(url: "https://github.com/FabrizioBrancati/Queuer.git", from: "3.0.0"),

Add the dependency to any targets you've declared in your manifest:

.target(
    name: "MyTarget", 
    dependencies: [
        .product(name: "Queuer", package: "Queuer"),
    ]
),

Usage

Shared Queuer

Queuer offers a shared instance that you can use to add operations to a centralized queue:

Queuer.shared.addOperation(operation)

Custom Queue

You can also create a custom queue:

let queue = Queuer(name: "MyCustomQueue")

You can even create a queue by defining the maxConcurrentOperationCount and the qualityOfService properties:

let queue = Queuer(name: "MyCustomQueue", maxConcurrentOperationCount: Int.max, qualityOfService: .default)

Create an Operation Block

You have three methods to add an Operation block.

  1. Directly on the queue(or Queuer.shared):

    queue.addOperation {
        /// Your task here
    }
    
  2. Creating a ConcurrentOperation with a block:

    let concurrentOperation = ConcurrentOperation { _ in
        /// Your task here
    }
    queue.addOperation(concurrentOperation)
    

[!NOTE] We will see how ConcurrentOperation works later.

Chained Operations

Chained Operations are Operations that add a dependency each other.

They follow the given array order, for example: [A, B, C] = A -> B -> C -> completionBlock.

let concurrentOperationA = ConcurrentOperation { _ in
    /// Your task A here
}
let concurrentOperationB = ConcurrentOperation { _ in
    /// Your task B here
}
queue.addChainedOperations([concurrentOperationA, concurrentOperationB]) {
    /// Your completion task here
}

You can also add a completionHandler after the queue creation with:

queue.addCompletionHandler {
    /// Your completion task here
}

Group Operations

Group Operations are Operations that handles a group of Operations with a completion handler.

Allows the execution of a block of Operations with a completion handler that will be called once all the operations are finished, for example: [A -> [[B & C & D] -> completionHandler] -> E] -> completionHandler. It should usually be used with a Chained Opetation.

let groupOperationA = GroupOperation(
    [
        ConcurrentOperation { _ in
            /// Your task A here
        },
        ConcurrentOperation { _ in
            /// Your task B here
        }
    ]
)

let concurrentOperationC = ConcurrentOperation { _ in
    /// Your task C here
}

queue.addChainedOperations([groupOperationA, concurrentOperationC]) {
    /// Your completion task here
}

In this case the output will be the following one: [[A & B -> completionHandler] -> C] -> completionHandler.

Queue States

There are a few method to handle the queue states.

  1. Cancel all Operations in a queue:

    queue.cancelAll()
    
  2. Pause a queue:

    queue.pause()
    

[!WARNING] By calling pause() you will not be sure that every Operation will be paused. If the Operation is already started it will not be on pause until it's a custom Operation that overrides pause() function.

  1. Resume a queue:

    queue.resume()
    

[!WARNING] To have a complete pause and resume states you must create a custom Operation that overrides pause() and resume() function.

  1. Wait until all Operations are finished:

    queue.waitUntilAllOperationsAreFinished()
    

[!IMPORTANT] This function means that the queue will blocks the current thread until all Operations are finished.

Synchronous Queue

Setting the maxConcurrentOperationCount property of a queue to 1 will make you sure that only one task at a time will be executed.

Asynchronous Operation

ConcurrentOperation is a class created to be subclassed. It allows synchronous and asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block.

You can create your custom ConcurrentOperation by subclassing it.

You must override execute() function and call the finish() function inside it, when the task has finished its job to notify the queue.

For convenience it has an init function with a completion block:

let concurrentOperation = ConcurrentOperation { _ in
    /// Your task here
}
concurrentOperation.addToQueue(queue)

Automatically Retry an Operation

An Operation is passed to every closure, with it you can set and handle the retry feature.

By default the retry feature is disabled, to enable it simply set the success property to false. With success to false the Operation will retry until reaches maximumRetries property value. To let the Operation know when everything is ok, you must set success to true.

With currentAttempt you can know at which attempt the Operation is.

let concurrentOperation = ConcurrentOperation { operation in
    /// Your task here
    if /* Successful */ {
      operation.success = true
    } else {
      operation.success = false
    }
}

Manually Retry an Operation

You can manually retry an Operation when you think that the execution will be successful.

An Operation is passed to every closure, with it you can set and handle the retry feature.

By default the manual retry feature is disabled, to enable it simply set the manualRetry property to true, you must do this outside of the execution closure. You must also set success to true or false to let the Operation know when is everything ok, like the automatic retry feature.

To let the Operation retry your execution closure, you have to call the retry() function. Be sure to call it at least maximumRetries times, it is not a problem if you call retry() more times than is needed, your execution closure will not be executed more times than the maximumRetries value.

let concurrentOperation = ConcurrentOperation { operation in
    /// Your task here
    if /* Successful */ {
      operation.success = true
    } else {
      operation.success = false
    }
}
concurrentOperation.manualRetry = true

/// Later on your code
concurrentOperation.retry()

[!CAUTION] If the retry() function is not called, you may block the entire queue.

Manually Finish an Operation

By default the Operation will finish its job when the execution closure is completed.

This means, if you have an asynchronous task insiede the closure, the Operation will finish before the task is completed.

If you want to finish it manually, you can set the manualFinish property to true and call the finish() function when the task is completed.

Call the finish(success:) function with success parameter to true or false to let the Operation know if the task was successful or not. If you don't explicitly set the success parameter, it will be set to true.

let concurrentOperation = ConcurrentOperation { operation in
    /// Your asynchonous task here
}
concurrentOperation.manualFinish = true

/// Later on your code in your asynchronous task
concurrentOperation.finish(success: true)

[!CAUTION] If you don't call the finish() function, your queue will be blocked and it will never ends.

Scheduler

A Scheduler is a struct that uses the GDC's DispatchSourceTimer to create a timer that can execute functions with a specified interval and quality of service.

let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) {
    /// Your task here
}

You can even create a Scheduler without the handler and set it later:

var schedule = Scheduler(deadline: .now(), repeating: .seconds(1))
schedule.setHandler {
    /// Your task here
}

With timer property you can access to all DispatchSourceTimer properties and functions, like cancel():

schedule.timer.cancel()

Semaphore

A Semaphore is a struct that uses the GCD's DispatchSemaphore to create a semaphore on the function and wait until it finish its job.

[!TIP] Is recommend to use a defer { semaphore.continue() } right after the Semaphore creation and wait() call.

let semaphore = Semaphore()
semaphore.wait()
defer { semaphore.continue() }
/// Your task here

You can even set a custom timeout, default is .distantFuture:

semaphore.wait(DispatchTime(uptimeNanoseconds: 1_000_000_000))

It's more useful if used inside an asynchronous task:

let concurrentOperation = ConcurrentOperation {
    /// Your task here
    semaphore.continue()
}
concurrentOperation.addToQueue(queue)
semaphore.wait()

Changelog

To see what has changed in recent versions of Queuer, see the CHANGELOG.md file.

Communication

  • If you need help, open an issue.
  • If you found a bug, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, see Contributing section.

Contributing

See CONTRIBUTING.md file.

License

Queuer is available under the MIT license. See the LICENSE file for more info.

GitHub

link
Stars: 1048
Last commit: 13 hours ago
Advertisement: IndiePitcher.com - Cold Email Software for Startups

Release Notes

The Phoenix
13 hours ago

Queuer 3.0.0

24 Apri 2024

[!WARNING] The goal of this release is to make the repo more maintainable. To do so, only Swift Package Manager will be supported. If you rely on any of the removed dependencies managers, like CocoaPods or Carthage, please stick to the previous version.

Queuer 2.1.1 is compatible with Swift 5.10, you can still use it in your projects.

Changed

  • Changed CI service to GitHub Actions
  • Changed minumum iOS version to 12.0 - #24
  • Changed minimum macOS version to 10.13
  • Changed minimum tvOS version to 12.0
  • Changed minimum watchOS version to 4.0
  • Changed minimum macCatalyst version to 13.0

Added

  • Added visionOS 1.0 support
  • Added full Linux support
  • Added manual finish feature to ConcurrentOperation class, more info on how to use it here - #28
  • Added new GroupOperation operation type, more info on how to use it here - #14 #17
  • Added support to Xcode 15.3 and Swift 5.10
  • Added macCatalyst support
  • Added Swift Package Index documentation support - #26 #30
  • Added Dependabot support

Fixed

  • Fixed a Scheduler bug that may prevent to correctly call the event handler

Improved

Removed

  • Removed SynchronousOperation. Use a queue with maxConcurrentOperationCount set to 1 to execute a synchronous queue
  • Removed isAsynchronous variable from ConcurrentOperation as always ignored by OperationQueues. You can override it anyway if you need to, since it's inferred from the Operation class
  • Removed hasFailed variable from ConcurrentOperation class as it was deprecated in version 2.0.1
  • Removed finish(_ hasFailed: Bool) function from ConcurrentOperation class as it was deprecated in version 2.0.1
  • Removed State Restoration feature as it was not fully working and never went out of beta
  • Removed SwiftLint support
  • Removed CocoaPods support
  • Removed Carthage support
  • Removed Coveralls support
  • Removed Slather support
  • Removed Jazzy support

Thanks to Kalzem, changmingw96, cristianilea-lateral, kradalby, mradzinski and marinofaggiana for this release.

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics