SwiftConcurrentCollections icon indicating copy to clipboard operation
SwiftConcurrentCollections copied to clipboard

Swift Concurrent Collections

SwiftConcurrentCollections

Intro

Swift Concurrent Collections (or SCC) is a library providing concurrent (thread-safe) implementations of some of default Swift collections. Similar to ones found in java.util.concurrent for Java.

Installation

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

Once you have your Swift package set up, adding SwiftConcurrentCollections as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/peterprokop/SwiftConcurrentCollections.git", .branch("master"))
]

Carthage

In your Xcode project folder do:

  • echo "github \"peterprokop/SwiftConcurrentCollections\" ~> 1.3.0" >> Cartfile (or use nano)
  • Run carthage update
  • Add SwiftConcurrentCollections to your carthage copy-frameworks phase
  • Add import SwiftConcurrentCollections in files where you plan to use it

Usage

Do import SwiftConcurrentCollections

Then you can use concurrent collections from different threads without fear of crashes or data corruption

let concurrentArray = ConcurrentArray<Int>()
concurrentArray.append(value)
print(concurrentArray[0])
let concurrentDictionary = ConcurrentDictionary<String, Int>()
concurrentDictionary[key] = value
print(concurrentDictionary[key])

Safe subscript

Safe array subscript: for atomicity of checking if specified index is in the array and getting element with that index use

if let element = concurrentArray[safe: index] {
    // ...
}

instead of

if index < concurrentArray.count {
    let element = concurrentArray[index]
    // ...
}

Priority queue

SCC provides both classical and concurrent priority queues

var priorityQueue = PriorityQueue<Int>(<)

priorityQueue.insert(3)
priorityQueue.insert(2)
priorityQueue.insert(1)

while priorityQueue.count > 0 {
    print(
        priorityQueue.pop(),
        terminator: " "
    )
    // Will print: 1 2 3
}

As you can see PriorityQueue<Int>(<) constructs min-queue, with PriorityQueue<Int>(>) you can get max-queue. If you need to reserve capacity right away, use PriorityQueue<Int>(capacity: 1024, comparator: <). ConcurrentPriorityQueue<Int>(<) creates a thread-safe version, with a very similar interface.