All Projects → ChimeHQ → OperationPlus

ChimeHQ / OperationPlus

Licence: BSD-3-Clause license
NSOperation's missing pieces

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to OperationPlus

Objcxx
Stars: ✭ 54 (-54.62%)
Mutual labels:  foundation, cocoa
Rearrange
Collection of utilities for interacting with NSRange and NSTextRange
Stars: ✭ 28 (-76.47%)
Mutual labels:  foundation, cocoa
ProcessEnv
Capture the shell environment of a Foundation app
Stars: ✭ 16 (-86.55%)
Mutual labels:  foundation, cocoa
Fruity
Rusty bindings for Apple libraries
Stars: ✭ 72 (-39.5%)
Mutual labels:  foundation, cocoa
WWDCNotes
WWDCNotes.com content
Stars: ✭ 343 (+188.24%)
Mutual labels:  cocoa
OutlineViewDiffableDataSource
Stop looking for NSOutlineViewDiffableDataSource, it’s here 👌
Stars: ✭ 96 (-19.33%)
Mutual labels:  cocoa
panthro
An implementation of XPath 3.0 in Objective-C/Cocoa
Stars: ✭ 45 (-62.18%)
Mutual labels:  cocoa
extensions-kit
📦 Collection of Swift+Apple Frameworks extensions for speeding up software development [iOS & iPadOS].
Stars: ✭ 71 (-40.34%)
Mutual labels:  foundation
NoticeBoard
请使用功能更强大的ProHUD: https://github.com/xaoxuu/ProHUD
Stars: ✭ 15 (-87.39%)
Mutual labels:  cocoa
foundation-server
(v1) A scalable cryptocurrency mining pool server written in Node.js
Stars: ✭ 45 (-62.18%)
Mutual labels:  foundation
articles-ko
Articles for NSHipster.co.kr
Stars: ✭ 18 (-84.87%)
Mutual labels:  cocoa
objc-lisp-bridge
A portable reader and bridge for interacting with Objective-C and Cocoa
Stars: ✭ 39 (-67.23%)
Mutual labels:  cocoa
AttributedStringWrapper
a simple packaging for NSAttributedString to make the developers easy to use
Stars: ✭ 16 (-86.55%)
Mutual labels:  cocoa
nimble-commander
Nimble Commander - dual-pane file manager for Mac
Stars: ✭ 147 (+23.53%)
Mutual labels:  cocoa
tools-android
Objective-C on Android with Foundation, CoreFoundation, and libdispatch.
Stars: ✭ 38 (-68.07%)
Mutual labels:  foundation
react-native-macos
Fork of https://github.com/ptmt/react-native-macos with more features
Stars: ✭ 22 (-81.51%)
Mutual labels:  cocoa
Swift-ISO8601-DurationParser
Swift ISO8601 Parser
Stars: ✭ 24 (-79.83%)
Mutual labels:  foundation
topologic
Visualiser for basic geometric primitives and fractals in arbitrary-dimensional spaces
Stars: ✭ 39 (-67.23%)
Mutual labels:  cocoa
WCSDateRange
Simple date range class.
Stars: ✭ 13 (-89.08%)
Mutual labels:  cocoa
reactive.foundation
reactive.foundation website
Stars: ✭ 18 (-84.87%)
Mutual labels:  foundation

Build Status License Platforms

OperationPlus

OperationPlus is a set of NSOperation subclasses and extensions on NSOperation/NSOperationQueue. Its goal is to fill in the API's missing pieces. You don't need to learn anything new to use it.

NSOperation has been around for a long time, and there are now two potential first-party alternatives, Combine and Swift concurrency. OperationPlus includes some facilities to help Combine and NSOperation interoperate conveniently.

Integration

Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/ChimeHQ/OperationPlus.git")
]

NSOperation Subclasses

  • BaseOperation: provides core functionality for easier NSOperation subclassing
  • AsyncOperation: convenience wrapper around BaseOperation for async support
  • AsyncBlockOperation: convenience class for inline async support
  • (Async)ProducerOperation: produces an output
  • (Async)ConsumerOperation: accepts an input from a ProducerOperation
  • (Async)ConsumerProducerOperation: accepts an input from a ProducerOperation and also produces an output

BaseOperation

This is a simple NSOperation subclass built for easier extensibility. It features:

  • Thread-safety
  • Timeout support
  • Easier cancellation handling
  • Stricter state checking
  • Built-in asynchrous support
  • Straight-foward customization
let a = BaseOperation(timeout: 5.0)

// NSOperation will happily allow you do this even
// if `a` has finished. `BaseOperation` will not.
a.addDependency(another)

// ...
public override func main() {
    // This will return true if your operation is cancelled, timed out,
    // or prematurely finished. ProducerOperation subclass state will be
    // handled correctly as well.
    if self.checkForCancellation() {
        return
    }
}
// ...

AsyncOperation

A BaseOperation subclass that can be used for your asynchronous operations. These are any operations that need to extend their lifetime past the main method.

import Foundation
import OperationPlus

class MyAsyncOperation: AsyncOperation {
    public override func main() {
        DispatchQueue.global().async {
            if self.checkForCancellation() {
                return
            }

            // do stuff

            self.finish()
        }
    }
}

There's also nothing special about this class at all -- it's there just for convenience. If you want, you can just subclass BaseOperation directly and override one method.

import Foundation
import OperationPlus

class MyAsyncOperation: BaseOperation {
    override open var isAsynchronous: Bool {
        return true
    }
}

ProducerOperation

A BaseOperation subclass that yields a value. Includes a completion handler to access the value.

import Foundation
import OperationPlus

class MyValueOperation: ProducerOperation<Int> {
    public override func main() {
        // do your computation

        self.finish(with: 42)
    }
}

// ...

let op = MyValueOperation()

op.resultCompletionBlock = { (value) in
    // use value here
}

AsyncProducerOperation

A variant of ProducerOperation that may produce a value after the main method has completed executing.

import Foundation
import OperationPlus

class MyAsyncOperation: AsyncProducerOperation<Int> {
    public override func main() {
        DispatchQueue.global().async {
            if self.checkForCancellation() {
                return
            }

            // do stuff

            self.finish(with: 42)
        }
    }
}

ConsumerOperation and AsyncConsumerOperation

A BaseOperation sublass that accepts the input of a ProducerOperation.

import Foundation
import OperationPlus

class MyConsumerOperation: ConsumerOperation<Int> {
    override func main() {
        guard let value = producerValue else {
            // handle failure in some way
        }
    }
    
    override func main(with value: Int) {
        // make use of value here, or automatically
        // fail if it wasn't successfully produced
    }
}

let op = MyConsumerOperation(producerOp: myIntProducerOperation)

AsyncBlockOperation

A play on NSBlockOperation, but makes it possible to support asynchronous completion without making an Operation subclass. Great for quick, inline work.

let op = AsyncBlockOperation { (completionBlock) in
    DispatchQueue.global().async {
        // do some async work here, just be certain to call
        // the completionBlock when done
        completionBlock()
    }
}

NSOperation/NSOperationQueue Extensions

Queue creation conveniences:

let a = OperationQueue(name: "myqueue")
let b = OperationQueue(name: "myqueue", maxConcurrentOperations: 1)
let c = OperationQueue.serialQueue()
let d = OperationQueue.serialQueue(named: "myqueue")

Enforcing runtime constraints on queue execution:

OperationQueue.preconditionMain()
OperationQueue.preconditionNotMain()

Consise dependencies:

queue.addOperation(op, dependency: opA)
queue.addOperation(op, dependencies: [opA, opB])
queue.addOperation(op, dependencies: Set([opA, opB]))

op.addDependencies([opA, opB])
op.addDependencies(Set([opA, opB]))

Queueing work when a queue's current operations are complete:

queue.currentOperationsFinished {
  print("all pending ops done")
}

Convenient inline functions:

queue.addAsyncOperation { (completionHandler) in
    DispatchQueue.global().async {
        // do some async work
        completionHandler()
    }
}

Async integration:

queue.addOperation {
    await asyncFunction1()
    await asyncFunction2()
}

let value = try await queue.addResultOperation {
    try await asyncValue()
}

Delays:

queue.addOperation(op, afterDelay: 5.0)
queue.addOperation(afterDelay: 5.0) {
  // work
}

Combine Integration

PublisherOperation

This ProducerOperation subclass takes a publisher. When executed, it creates a subscription and outputs the results.

op.publisher() // AnyPublisher<Void, Never>

producerOp.outputPublisher() // AnyPublisher<Output, Never>
publisher.operation() // PublisherOperation
publisher.execute(on: queue) // subscribes and executes chain on queue and returns a publisher for result

XCTest Support

OperationTestingPlus is an optional micro-framework to help make your XCTest-based tests a little nicer. When using Carthage, it is built as a static framework to help ease integration with your testing targets.

FulfillExpectationOperation

A simple NSOperation that will fulfill an XCTestExpectation when complete. Super-useful when used with dependencies on your other operations.

NeverFinishingOperation

A great way to test out your Operations' timeout behaviors.

OperationExpectation

An XCTestExpectation sublass to make testing async operations a little more XCTest-like.

let op = NeverFinishingOperation()

let expectation = OperationExpectation(operation: op)
expectation.isInverted = true

wait(for: [expectation], timeout: 1.0)

Suggestions or Feedback

We'd love to hear from you! Get in touch via twitter, an issue, or a pull request.

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].