• This repository has been archived on 05/Jul/2024
  • Stars
    star
    128
  • Rank 281,044 (Top 6 %)
  • Language
    Swift
  • License
    BSD 3-Clause "New...
  • Created almost 6 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

NSOperation's missing pieces

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 an issue or 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.

More Repositories

1

Impact

Crash capturing library for Apple platforms
C
431
star
2

Neon

A Swift library for efficient, flexible content-based text styling
Swift
320
star
3

Chime

An editor for macOS
Swift
303
star
4

SwiftTreeSitter

Swift API for the tree-sitter incremental parsing system
Swift
264
star
5

ConcurrencyPlus

Utilities for working with Swift Concurrency
Swift
253
star
6

Meter

Library for interacting with MetricKit
Swift
217
star
7

SwiftLSPClient

A Swift library for interacting with Language Server Protocol implementations
Swift
103
star
8

LanguageClient

Language Server Protocol (LSP) client for Swift
Swift
96
star
9

TextStory

Happier, more flexible NSTextStorage
Swift
92
star
10

Rearrange

Swift library for working with ranges types: NSRange, IndexSet, and String.Index
Swift
69
star
11

WindowTreatment

Tools for happier work with NSWindow
Swift
63
star
12

LanguageServerProtocol

Swift library for working with Language Server Protocol (LSP)
Swift
56
star
13

ChimeKit

Framework for building Chime extensions
Swift
49
star
14

TextViewPlus

Make life better with NSTextView+TextKit 1/2
Swift
46
star
15

OAuthenticator

OAuth 2.0 request authentication
Swift
46
star
16

TextFormation

Rules system for live typing completions
Swift
46
star
17

Extendable

A set of utilities for more pleasant work with ExtensionKit
Swift
43
star
18

Wells

A lightweight diagnostics report submission system
Swift
40
star
19

AsyncXPCConnection

Concurrency support for NSXPCConnection
Swift
40
star
20

ProcessService

Host an executable within an XPC service
Swift
39
star
21

UITestingPlus

Utilities for working with XCUI testing
Swift
38
star
22

KeyCodes

AppKit Carbon key codes to UIKey-compatible enums
Swift
35
star
23

MeterReporter

Lightweight MetricKit-based diagnostics reporting
Swift
33
star
24

NicerTouchBar

Utilities for a more pleasant NSTouchBar development experience
Swift
33
star
25

TextViewBenchmark

A suite of performance tests for macOS text views
Swift
32
star
26

Flexer

Lexing library for Swift
Swift
31
star
27

ContainedDocument

Nested NSDocuments
Swift
26
star
28

JSONRPC

Swift library for JSON-RPC
Swift
25
star
29

ProcessEnv

Capture the shell environment of a Foundation app
Swift
25
star
30

ThemePark

A Swift library for working with syntax highlighting/IDE themes
Swift
25
star
31

Glyph

Make life with TextKit better
Swift
24
star
32

Dusk

Micro-framework to aid in supporting Dark Mode on macOS
Swift
21
star
33

ScrollViewPlus

A more pleasant NSScrollView experience
Swift
16
star
34

Background

Background Tasks and Networking
Swift
16
star
35

Welp

Tooling for macOS help books
Swift
15
star
36

XPCConnectionSession

Backwards-compatible implementation of XPCSession
Swift
13
star
37

EditorConfig

A Swift library for working with .editorconfig files
Swift
13
star
38

GlobPattern

Swift package to parse and evaluate glob patterns
Swift
13
star
39

Outline

Lazy SwiftUI wrapper for NSOutlineView
Swift
12
star
40

LanguageServer

Language Server Protocol server infrastructure for Swift
Swift
11
star
41

ImpactMeterAdapter

Impact crash reports as a Meter diagnostic source
Swift
11
star
42

Gramophone

Swift library for working with Extended Backus–Naur Form (EBNF) notation and grammars.
Swift
11
star
43

CoreSymbolication

Headers and package for CoreSymbolication
Swift
11
star
44

Ligature

Text selection, grouping, indentation, and manipulation in Swift
Swift
10
star
45

ViewPlus

Make working with NSView more pleasant
Swift
10
star
46

UnifiedLoggingPlus

Micro-framework for making OSLog more pleasant
Swift
10
star
47

Textbook

Easier text views and SwiftUI
Swift
10
star
48

chime-swift

A Chime extension for Swift
Swift
9
star
49

SwiftCoreSymbolication

Swift wrappers for CoreSymbolication
Swift
9
star
50

DebugAdapterProtocol

Swift library for working with Debug Adapter Protocol (DAP)
Swift
8
star
51

SourceView

A TextKit 2 `NSTextView` subclass built specifically to work with source code
Swift
7
star
52

RelativeCollections

Swift collection types that support efficient storage of order-relative values.
Swift
7
star
53

IBeam

A Swift library for multi-cursor support
Swift
7
star
54

paddleapi

Go implementation of the Paddle API
Go
6
star
55

MetricKitViewer

A really simple app for viewing MetricKit payloads
Swift
5
star
56

Lowlight

A simple syntax processing system that prioritizes latency over correctness
Swift
5
star
57

chime-ruby

A Chime extension for Ruby
Swift
4
star
58

chime-rust

A Chime extension for Rust
Swift
4
star
59

STTextView-Plugin-TextFormation

Source Code Typing Completions
Swift
4
star
60

gogsym

Go library for reading GSYM files
Go
3
star
61

chime-markdown

A Chime extension for Markdown
3
star
62

LanguageServerScripts

A collection of standardized scripts for managing LSP language servers with a Swift API
Shell
3
star
63

chime-elixir

A Chime extension for Elixir
Swift
2
star
64

binarycursor

Go binary data reader
Go
2
star
65

chime-python

A Chime extension for Rust
Swift
2
star
66

chime-go

A Chime extension for Go
Swift
1
star
67

chime-clojure

A Chime extension for Clojure
Swift
1
star
68

marpa-xcframework

XCFramework wrapper for libmarpa
C
1
star
69

Borderline

System for working with text line numbers in Swift
Swift
1
star