Create thread safe array in Swift - ios
I have a threading problem in Swift. I have an array with some objects in it. Over a delegate the class gets new objects about every second. After that I have to check if the objects are already in the array, so I have to update the object, otherwise I have to delete / add the new object.
If I add a new object I have to fetch some data over the network first. This is handelt via a block.
Now my problem is, how to I synchronic this tasks?
I have tried a dispatch_semaphore, but this one blocks the UI, until the block is finished.
I have also tried a simple bool variable, which checks if the block is currently executed and skips the compare method meanwhile.
But both methods are not ideal.
What's the best way to manage the array, I don't wanna have duplicate data in the array.
Update for Swift
The recommended pattern for thread-safe access is using dispatch barrier:
let queue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent)
// write
queue.async(flags: .barrier) {
// perform writes on data
}
// read
var value: ValueType!
queue.sync {
// perform read and assign value
}
return value
I don't know why people take such complex approaches to such a simple thing
Don't abuse DispatchQueues for locking. Using queue.sync is nothing more than acquiring a lock and dispatching work to another thread while the lock (DispatchGroup) waits. It is not just unnecessary, but also can have side effects depending on what you are locking. You can look it up yourself in the GCD Source.
Also GCD does not mix well with the new structured concurrency APIs!
Don't use objc_sync_enter/exit, those are used by ObjCs #synchronized which will implicitly bridge Swift collections to a ObjC counterpart, which is also unnecessary. And it is a legacy API.
Just define a lock, and guard your collection access.
var lock = NSLock()
var a = [1, 2, 3]
lock.lock()
a.append(4)
lock.unlock()
If you want to make your life a bit easier, define a small extension.
extension NSLock {
#discardableResult
func with<T>(_ block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}
let lock = NSLock()
var a = [1, 2, 3]
lock.with { a.append(4) }
You can also define a #propertyWrapper to make your member vars atomic.
#propertyWrapper
struct Atomic<Value> {
private let lock = NSLock()
private var value: Value
init(default: Value) {
self.value = `default`
}
var wrappedValue: Value {
get {
lock.lock()
defer { lock.unlock() }
return value
}
set {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
}
Last but not least for primitive atomic types there is also Swift Atomics
Kirsteins's answer is correct, but for convenience, I've updated that answer with Amol Chaudhari and Rob's suggestions for using a concurrent queue with async barrier to allow concurrent reads but block on writes.
I've also wrapped some other array functions that were useful to me.
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_CONCURRENT)
public func append(newElement: T) {
dispatch_barrier_async(self.accessQueue) {
self.array.append(newElement)
}
}
public func removeAtIndex(index: Int) {
dispatch_barrier_async(self.accessQueue) {
self.array.removeAtIndex(index)
}
}
public var count: Int {
var count = 0
dispatch_sync(self.accessQueue) {
count = self.array.count
}
return count
}
public func first() -> T? {
var element: T?
dispatch_sync(self.accessQueue) {
if !self.array.isEmpty {
element = self.array[0]
}
}
return element
}
public subscript(index: Int) -> T {
set {
dispatch_barrier_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!
dispatch_sync(self.accessQueue) {
element = self.array[index]
}
return element
}
}
}
UPDATE
This is the same code, updated for Swift3.
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess", attributes: .concurrent)
public func append(newElement: T) {
self.accessQueue.async(flags:.barrier) {
self.array.append(newElement)
}
}
public func removeAtIndex(index: Int) {
self.accessQueue.async(flags:.barrier) {
self.array.remove(at: index)
}
}
public var count: Int {
var count = 0
self.accessQueue.sync {
count = self.array.count
}
return count
}
public func first() -> T? {
var element: T?
self.accessQueue.sync {
if !self.array.isEmpty {
element = self.array[0]
}
}
return element
}
public subscript(index: Int) -> T {
set {
self.accessQueue.async(flags:.barrier) {
self.array[index] = newValue
}
}
get {
var element: T!
self.accessQueue.sync {
element = self.array[index]
}
return element
}
}
}
My approach to this problem was using serial dispatch queue, to synchronise access to boxed array. It will block the thread when you try to get the value at index and queue is really busy, but that's the problem with locks as well.
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_SERIAL)
public func append(newElement: T) {
dispatch_async(self.accessQueue) {
self.array.append(newElement)
}
}
public subscript(index: Int) -> T {
set {
dispatch_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!
dispatch_sync(self.accessQueue) {
element = self.array[index]
}
return element
}
}
}
var a = SynchronizedArray<Int>()
a.append(1)
a.append(2)
a.append(3)
// can be empty as this is non-thread safe access
println(a.array)
// thread-safe synchonized access
println(a[0])
println(a[1])
println(a[2])
Details
Xcode 10.1 (10B61), Swift 4.2
Xcode 10.2.1 (10E1001), Swift 5
Solution
import Foundation
// https://developer.apple.com/documentation/swift/rangereplaceablecollection
struct AtomicArray<T>: RangeReplaceableCollection {
typealias Element = T
typealias Index = Int
typealias SubSequence = AtomicArray<T>
typealias Indices = Range<Int>
fileprivate var array: Array<T>
var startIndex: Int { return array.startIndex }
var endIndex: Int { return array.endIndex }
var indices: Range<Int> { return array.indices }
func index(after i: Int) -> Int { return array.index(after: i) }
private var semaphore = DispatchSemaphore(value: 1)
fileprivate func _wait() { semaphore.wait() }
fileprivate func _signal() { semaphore.signal() }
}
// MARK: - Instance Methods
extension AtomicArray {
init<S>(_ elements: S) where S : Sequence, AtomicArray.Element == S.Element {
array = Array<S.Element>(elements)
}
init() { self.init([]) }
init(repeating repeatedValue: AtomicArray.Element, count: Int) {
let array = Array(repeating: repeatedValue, count: count)
self.init(array)
}
}
// MARK: - Instance Methods
extension AtomicArray {
public mutating func append(_ newElement: AtomicArray.Element) {
_wait(); defer { _signal() }
array.append(newElement)
}
public mutating func append<S>(contentsOf newElements: S) where S : Sequence, AtomicArray.Element == S.Element {
_wait(); defer { _signal() }
array.append(contentsOf: newElements)
}
func filter(_ isIncluded: (AtomicArray.Element) throws -> Bool) rethrows -> AtomicArray {
_wait(); defer { _signal() }
let subArray = try array.filter(isIncluded)
return AtomicArray(subArray)
}
public mutating func insert(_ newElement: AtomicArray.Element, at i: AtomicArray.Index) {
_wait(); defer { _signal() }
array.insert(newElement, at: i)
}
mutating func insert<S>(contentsOf newElements: S, at i: AtomicArray.Index) where S : Collection, AtomicArray.Element == S.Element {
_wait(); defer { _signal() }
array.insert(contentsOf: newElements, at: i)
}
mutating func popLast() -> AtomicArray.Element? {
_wait(); defer { _signal() }
return array.popLast()
}
#discardableResult mutating func remove(at i: AtomicArray.Index) -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.remove(at: i)
}
mutating func removeAll() {
_wait(); defer { _signal() }
array.removeAll()
}
mutating func removeAll(keepingCapacity keepCapacity: Bool) {
_wait(); defer { _signal() }
array.removeAll()
}
mutating func removeAll(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) rethrows {
_wait(); defer { _signal() }
try array.removeAll(where: shouldBeRemoved)
}
#discardableResult mutating func removeFirst() -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.removeFirst()
}
mutating func removeFirst(_ k: Int) {
_wait(); defer { _signal() }
array.removeFirst(k)
}
#discardableResult mutating func removeLast() -> AtomicArray.Element {
_wait(); defer { _signal() }
return array.removeLast()
}
mutating func removeLast(_ k: Int) {
_wait(); defer { _signal() }
array.removeLast(k)
}
#inlinable public func forEach(_ body: (Element) throws -> Void) rethrows {
_wait(); defer { _signal() }
try array.forEach(body)
}
mutating func removeFirstIfExist(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) {
_wait(); defer { _signal() }
guard let index = try? array.firstIndex(where: shouldBeRemoved) else { return }
array.remove(at: index)
}
mutating func removeSubrange(_ bounds: Range<Int>) {
_wait(); defer { _signal() }
array.removeSubrange(bounds)
}
mutating func replaceSubrange<C, R>(_ subrange: R, with newElements: C) where C : Collection, R : RangeExpression, T == C.Element, AtomicArray<Element>.Index == R.Bound {
_wait(); defer { _signal() }
array.replaceSubrange(subrange, with: newElements)
}
mutating func reserveCapacity(_ n: Int) {
_wait(); defer { _signal() }
array.reserveCapacity(n)
}
public var count: Int {
_wait(); defer { _signal() }
return array.count
}
public var isEmpty: Bool {
_wait(); defer { _signal() }
return array.isEmpty
}
}
// MARK: - Get/Set
extension AtomicArray {
// Single action
func get() -> [T] {
_wait(); defer { _signal() }
return array
}
mutating func set(array: [T]) {
_wait(); defer { _signal() }
self.array = array
}
// Multy actions
mutating func get(closure: ([T])->()) {
_wait(); defer { _signal() }
closure(array)
}
mutating func set(closure: ([T]) -> ([T])) {
_wait(); defer { _signal() }
array = closure(array)
}
}
// MARK: - Subscripts
extension AtomicArray {
subscript(bounds: Range<AtomicArray.Index>) -> AtomicArray.SubSequence {
get {
_wait(); defer { _signal() }
return AtomicArray(array[bounds])
}
}
subscript(bounds: AtomicArray.Index) -> AtomicArray.Element {
get {
_wait(); defer { _signal() }
return array[bounds]
}
set(value) {
_wait(); defer { _signal() }
array[bounds] = value
}
}
}
// MARK: - Operator Functions
extension AtomicArray {
static func + <Other>(lhs: Other, rhs: AtomicArray) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element {
return AtomicArray(lhs + rhs.get())
}
static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element {
return AtomicArray(lhs.get() + rhs)
}
static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : RangeReplaceableCollection, AtomicArray.Element == Other.Element {
return AtomicArray(lhs.get() + rhs)
}
static func + (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> AtomicArray {
return AtomicArray(lhs.get() + rhs.get())
}
static func += <Other>(lhs: inout AtomicArray, rhs: Other) where Other : Sequence, AtomicArray.Element == Other.Element {
lhs._wait(); defer { lhs._signal() }
lhs.array += rhs
}
}
// MARK: - CustomStringConvertible
extension AtomicArray: CustomStringConvertible {
var description: String {
_wait(); defer { _signal() }
return "\(array)"
}
}
// MARK: - Equatable
extension AtomicArray where Element : Equatable {
func split(separator: Element, maxSplits: Int, omittingEmptySubsequences: Bool) -> [ArraySlice<Element>] {
_wait(); defer { _signal() }
return array.split(separator: separator, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)
}
func firstIndex(of element: Element) -> Int? {
_wait(); defer { _signal() }
return array.firstIndex(of: element)
}
func lastIndex(of element: Element) -> Int? {
_wait(); defer { _signal() }
return array.lastIndex(of: element)
}
func starts<PossiblePrefix>(with possiblePrefix: PossiblePrefix) -> Bool where PossiblePrefix : Sequence, Element == PossiblePrefix.Element {
_wait(); defer { _signal() }
return array.starts(with: possiblePrefix)
}
func elementsEqual<OtherSequence>(_ other: OtherSequence) -> Bool where OtherSequence : Sequence, Element == OtherSequence.Element {
_wait(); defer { _signal() }
return array.elementsEqual(other)
}
func contains(_ element: Element) -> Bool {
_wait(); defer { _signal() }
return array.contains(element)
}
static func != (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool {
lhs._wait(); defer { lhs._signal() }
rhs._wait(); defer { rhs._signal() }
return lhs.array != rhs.array
}
static func == (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool {
lhs._wait(); defer { lhs._signal() }
rhs._wait(); defer { rhs._signal() }
return lhs.array == rhs.array
}
}
Usage sample 1
import Foundation
// init
var array = AtomicArray<Int>()
print(array)
array = AtomicArray(repeating: 0, count: 5)
print(array)
array = AtomicArray([1,2,3,4,5,6,7,8,9])
print(array)
// add
array.append(0)
print(array)
array.append(contentsOf: [5,5,5])
print(array)
// filter
array = array.filter { $0 < 7 }
print(array)
// map
let strings = array.map { "\($0)" }
print(strings)
// insert
array.insert(99, at: 5)
print(array)
array.insert(contentsOf: [2, 2, 2], at: 0)
print(array)
// pop
_ = array.popLast()
print(array)
_ = array.popFirst()
print(array)
// remove
array.removeFirst()
print(array)
array.removeFirst(3)
print(array)
array.remove(at: 2)
print(array)
array.removeLast()
print(array)
array.removeLast(5)
print(array)
array.removeAll { $0%2 == 0 }
print(array)
array = AtomicArray([1,2,3,4,5,6,7,8,9,0])
array.removeSubrange(0...2)
print(array)
array.replaceSubrange(0...2, with: [0,0,0])
print(array)
array.removeAll()
print(array)
array.set(array: [1,2,3,4,5,6,7,8,9,0])
print(array)
// subscript
print(array[0])
array[0] = 100
print(array)
print(array[1...4])
// operator functions
array = [1,2,3] + AtomicArray([4,5,6])
print(array)
array = AtomicArray([4,5,6]) + [1,2,3]
print(array)
array = AtomicArray([1,2,3]) + AtomicArray([4,5,6])
print(array)
Usage sample 2
import Foundation
var arr = AtomicArray([0,1,2,3,4,5])
for i in 0...1000 {
// Single actions
DispatchQueue.global(qos: .background).async {
usleep(useconds_t(Int.random(in: 100...10000)))
let num = i*i
arr.append(num)
print("arr.append(\(num)), background queue")
}
DispatchQueue.global(qos: .default).async {
usleep(useconds_t(Int.random(in: 100...10000)))
arr.append(arr.count)
print("arr.append(\(arr.count)), default queue")
}
// multy actions
DispatchQueue.global(qos: .utility).async {
arr.set { array -> [Int] in
var newArray = array
newArray.sort()
print("sort(), .utility queue")
return newArray
}
}
}
A minor detail: In Swift 3 (at least in Xcode 8 Beta 6), the syntax for queues changed significantly. The important changes to #Kirsteins' answer will be:
private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess")
txAccessQueue.async() {
// Your async code goes here...
}
txAccessQueue.sync() {
// Your sync code goes here...
}
Swift-Nio & Vapor Swift
For those of you using Swift-Nio (or Vapor Swift which is based on Swift-Nio), there's a built in solution for this problem:
class MyClass {
let lock = Lock()
var myArray: Array<Int> = []
func networkRequestWhatEver() {
lock.withLock {
array.append(someValue)
}
}
}
Note that you should use the same Lock object when modifing the same Array object (or Dictionary, etc.).
https://github.com/apple/swift-nio/blob/5e728b57862ce9e13877ff1edc9249adc933070a/Sources/NIOConcurrencyHelpers/lock.swift#L15
Thread-safe Data Structures with Actors
As of Swift 5.5 you can express this with an actor:
actor SyncArray<T> {
private var buffer: [T]
init<S: Sequence>(_ elements: S) where S.Element == T {
buffer = Array(elements)
}
var count: Int {
buffer.count
}
func append(_ element: T) {
buffer.append(element)
}
#discardableResult
func remove(at index: Int) -> T {
buffer.remove(at: index)
}
}
Not only it makes the code simpler and less error prone, but it makes more explicit the potential race condition pointed out in an other answer:
Task {
let array = SyncArray([1])
if await array.count == 1 {
await array.remove(at: 0)
}
}
There are two suspension points here, meaning that by the time .remove(at:) is called, the array count could have changed.
Such read-then-write operation must be atomic to be consistent, thus it should be defined as a method on the actor instead:
extension SyncArray {
func removeLastIfSizeOfOne() {
if buffer.count == 1 {
buffer.remove(at: 0)
}
}
}
Above, the absence of suspension points indicates that the operation is performed atomically. Another solution that works without writing an extension is to use the isolated keyword like this:
func removeLastIfSizeOfOne<T>(_ array: isolated SyncArray<T>) {
if array == 1 {
array(at: 0)
}
}
This will isolate the passed actor for the duration of the whole call instead of at each of its suspension points. Calling this function requires only one suspension point.
Here is the answer for Swift 4,
let queue = DispatchQueue(label: "com.readerWriter", qos: .background, attributes: .concurrent)
var safeArray: [String] = []
subscript(index: Int) -> String {
get {
queue.sync {
return safeArray[index]
}
}
set(newValue) {
queue.async(flags: .barrier) { [weak self] in
self?.safeArray[index] = newValue
}
}
}
I think dispatch_barriers are worth looking into. Using gcd for synchronicity is more intuitive to me than using synchronize keyword to avoid state mutation from multiple threads.
https://mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html
Approach:
Use DispatchQueue to synchronise
Refer:
http://basememara.com/creating-thread-safe-arrays-in-swift/
Code:
Below is a crude implementation of a thread safe array, you can fine tune it.
public class ThreadSafeArray<Element> {
private var elements : [Element]
private let syncQueue = DispatchQueue(label: "Sync Queue",
qos: .default,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: nil)
public init() {
elements = []
}
public init(_ newElements: [Element]) {
elements = newElements
}
//MARK: Non-mutating
public var first : Element? {
return syncQueue.sync {
elements.first
}
}
public var last : Element? {
return syncQueue.sync {
elements.last
}
}
public var count : Int {
return syncQueue.sync {
elements.count
}
}
public subscript(index: Int) -> Element {
get {
return syncQueue.sync {
elements[index]
}
}
set {
syncQueue.sync(flags: .barrier) {
elements[index] = newValue
}
}
}
public func reversed() -> [Element] {
return syncQueue.sync {
elements.reversed()
}
}
public func flatMap<T>(_ transform: (Element) throws -> T?) rethrows -> [T] {
return try syncQueue.sync {
try elements.flatMap(transform)
}
}
public func filter(_ isIncluded: (Element) -> Bool) -> [Element] {
return syncQueue.sync {
elements.filter(isIncluded)
}
}
//MARK: Mutating
public func append(_ element: Element) {
syncQueue.sync(flags: .barrier) {
elements.append(element)
}
}
public func append<S>(contentsOf newElements: S) where Element == S.Element, S : Sequence {
syncQueue.sync(flags: .barrier) {
elements.append(contentsOf: newElements)
}
}
public func remove(at index: Int) -> Element? {
var element : Element?
syncQueue.sync(flags: .barrier) {
if elements.startIndex ..< elements.endIndex ~= index {
element = elements.remove(at: index)
}
else {
element = nil
}
}
return element
}
}
extension ThreadSafeArray where Element : Equatable {
public func index(of element: Element) -> Int? {
return syncQueue.sync {
elements.index(of: element)
}
}
}
firstly, objc_sync_enter not works
objc_sync_enter(array)
defer {
objc_sync_exit(array)
}
reason objc_sync_enter / objc_sync_exit not working with DISPATCH_QUEUE_PRIORITY_LOW
objc_sync_enter is an extremely low-level primitive, and isn't intended to be used directly. It's an implementation detail of the old #synchronized system in ObjC.
for swift, should use like this, just as #Kirsteins said, and I suggest sync instead of async:
private let syncQueue = DispatchQueue(label:"com.test.LockQueue")
func test(){
self.syncQueue.sync{
// thread safe code here
}
}
If you want thread-safe interaction with your array, you must synchronize your access. There are many alternatives suggested (and a few that have been omitted), so let us survey the various synchronization alternatives:
Serial dispatch queue: This is a straightforward and intuitive GCD pattern.
Reader-writer pattern with concurrent queue: This is an elegant refinement of the serial dispatch queue pattern, using concurrent queue with asynchronous “writes” (so the caller does not wait for the write to finish) with a barrier (to prevent any interaction concurrent with a “write”), but it offers concurrent “reads” (allowing greater concurrency during “reads”). This is a sophisticated and appealing pattern, but in practice, it is only useful if the benefits of concurrent “reads” and asynchronous “writes” outweigh the GCD overhead.
Locks:
NSLock is a fast and simple locking mechanism that is more performant than any of the GCD alternatives for most scenarios:
extension NSLocking {
func synchronized<T>(_ block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}
os_unfair_lock is another locking mechanism, which is even faster than NSLock, but is a little more complicated to use from Swift. See https://stackoverflow.com/a/66525671/1271826. But in those rare cases where performance is of paramount concern, unfair locks are a compelling solution.
The Objective-C objc_sync_enter and objc_sync_exit API: This is not of practical interest in the Swift world.
Semaphores: It is conceptually similar to lock-based approaches, but is generally slower than any of the lock-based approaches and can be disregarded in this conversation.
Actors: A synchronization mechanism provided by the Swift 5.5 concurrency system. See Protect mutable state with Swift actors.
In short, if using async-await, actors are the logical alternative. If not yet adopting the Swift concurrency system, I would gravitate to a lock-based approach (which is simple and fast) or, in rare cases, the GCD reader-writer approach.
In practice, the choice of synchronization mechanism is not relevant in most use cases. (And if you are doing so many synchronizations that the performance difference becomes material, you might want to consider how to reduce the number of synchronization points before dwelling on the particular mechanism.) That having been said, the older synchronization mechanisms (semaphores, objc_sync_enter, etc.) simply would not be contemplated anymore.
Having outlined the possible synchronization mechanisms, the next question is at what level one performs the synchronization. Specifically, more than once, property wrappers for the entire array have been proposed. This is, invariably, the wrong place to synchronize. The property wrapper approach provides atomic access to the array (which is not quite the same thing as thread-safety), but you generally need a higher level of abstraction. E.g. if one thread is adding elements and while another is reading or removing, you often want each of these high-level tasks to be synchronized, not just the individual accesses of the array.
To improve the accepted answer I would suggest using defer:
objc_sync_enter(array)
defer {
objc_sync_exit(array)
}
// manipulate the array
and the second one
func sync(lock: NSObject, closure: () -> Void) {
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
closure()
}
Swift Thread safe collection
The main and most common idea of making something(e.g. Collection) thread safe in Swift is:
Custom(local) concurrent queue
Synchronous reading. Reading a critical section(shared resource) via sync
Asynchronous writing with barrier
[Swift Thread safe singleton]
There's a great answer here which is threadsafe and doesn't block concurrent reads: https://stackoverflow.com/a/15936959/2050665
It's written in Objective C, but porting to Swift is trivial.
#property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue;
#property (nonatomic, strong) NSObject *thing;
- (id)init {
...
_thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT);
...
}
- (NSObject *)thing {
__block NSObject *thing;
dispatch_sync(self.thingQueue, ^{
thing = _thing;
});
return thing;
}
- (void)setThing:(NSObject *)thing {
dispatch_barrier_async(self.thingQueue, ^{
_thing = thing;
});
}
Credit to https://stackoverflow.com/users/97337/rob-napier
Related
Swift thread safe array
I want to create thread-safe array for piping data between threads public class SyncArray<T> { public var dataArray = [T]() private var semaphore = DispatchSemaphore(value: 1) public init() { } private func wait() { semaphore.wait() } private func signal() { semaphore.signal() } public func count() -> Int { var count = 0; wait(); defer { signal() } count = dataArray.count return count; } public func unshift() -> T? { var firstEl:T? = nil wait(); defer { signal() } if(self.count() > 0){ firstEl = dataArray.removeFirst() } return firstEl; } public func pop() -> T? { var lastEl:T? = nil wait(); defer { signal() } if(self.count() > 0){ lastEl = dataArray.popLast() } return lastEl; } public func append(value: T) -> Void { wait(); defer { signal() } dataArray.append(value) } } Pipe data let buff = SyncArray<Container>() DispatchQueue.global().async { do { let dataSource = getDataSource() for i in 0 ..< dataSource.length{ buff.append(value: dataSource[i]) } } DispatchQueue.global().async { while(true) { let data = buff.unshift() } } The idea is to pipe data between threads. For some reason buff.append and buff.unshift deadlocks eachother i tried allso public func count() -> Int { wait(); count = dataArray.count signal() return count; } Same result. Please, advise what am I doing wrong. I feel the fix should be super simple. Thanks!
Your problem is that unshift calls count. unshift is already holding the semaphore, but the first thing that count does is call wait, which causes a deadlock. You have the same problem in popLast. Since you already have exclusive access to the array you can simply use its isEmpty property. public func unshift() -> T? { var firstEl:T? = nil wait(); defer { signal() } if !dataArray.isEmpty { firstEl = dataArray.removeFirst() } return firstEl; } public func pop() -> T? { var lastEl:T? = nil wait(); defer { signal() } if !dataArray.isEmpty { lastEl = dataArray.popLast() } return lastEl; } You could also replace your DispatchSemaphore with a NSRecursiveLock since you don't need the counting behaviour of a semaphore. NSRecursiveLock can be locked multiple times by the same thread without causing a deadlock.
Appending items to an array [duplicate]
I have a threading problem in Swift. I have an array with some objects in it. Over a delegate the class gets new objects about every second. After that I have to check if the objects are already in the array, so I have to update the object, otherwise I have to delete / add the new object. If I add a new object I have to fetch some data over the network first. This is handelt via a block. Now my problem is, how to I synchronic this tasks? I have tried a dispatch_semaphore, but this one blocks the UI, until the block is finished. I have also tried a simple bool variable, which checks if the block is currently executed and skips the compare method meanwhile. But both methods are not ideal. What's the best way to manage the array, I don't wanna have duplicate data in the array.
Update for Swift The recommended pattern for thread-safe access is using dispatch barrier: let queue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent) // write queue.async(flags: .barrier) { // perform writes on data } // read var value: ValueType! queue.sync { // perform read and assign value } return value
I don't know why people take such complex approaches to such a simple thing Don't abuse DispatchQueues for locking. Using queue.sync is nothing more than acquiring a lock and dispatching work to another thread while the lock (DispatchGroup) waits. It is not just unnecessary, but also can have side effects depending on what you are locking. You can look it up yourself in the GCD Source. Also GCD does not mix well with the new structured concurrency APIs! Don't use objc_sync_enter/exit, those are used by ObjCs #synchronized which will implicitly bridge Swift collections to a ObjC counterpart, which is also unnecessary. And it is a legacy API. Just define a lock, and guard your collection access. var lock = NSLock() var a = [1, 2, 3] lock.lock() a.append(4) lock.unlock() If you want to make your life a bit easier, define a small extension. extension NSLock { #discardableResult func with<T>(_ block: () throws -> T) rethrows -> T { lock() defer { unlock() } return try block() } } let lock = NSLock() var a = [1, 2, 3] lock.with { a.append(4) } You can also define a #propertyWrapper to make your member vars atomic. #propertyWrapper struct Atomic<Value> { private let lock = NSLock() private var value: Value init(default: Value) { self.value = `default` } var wrappedValue: Value { get { lock.lock() defer { lock.unlock() } return value } set { lock.lock() defer { lock.unlock() } value = newValue } } } Last but not least for primitive atomic types there is also Swift Atomics
Kirsteins's answer is correct, but for convenience, I've updated that answer with Amol Chaudhari and Rob's suggestions for using a concurrent queue with async barrier to allow concurrent reads but block on writes. I've also wrapped some other array functions that were useful to me. public class SynchronizedArray<T> { private var array: [T] = [] private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_CONCURRENT) public func append(newElement: T) { dispatch_barrier_async(self.accessQueue) { self.array.append(newElement) } } public func removeAtIndex(index: Int) { dispatch_barrier_async(self.accessQueue) { self.array.removeAtIndex(index) } } public var count: Int { var count = 0 dispatch_sync(self.accessQueue) { count = self.array.count } return count } public func first() -> T? { var element: T? dispatch_sync(self.accessQueue) { if !self.array.isEmpty { element = self.array[0] } } return element } public subscript(index: Int) -> T { set { dispatch_barrier_async(self.accessQueue) { self.array[index] = newValue } } get { var element: T! dispatch_sync(self.accessQueue) { element = self.array[index] } return element } } } UPDATE This is the same code, updated for Swift3. public class SynchronizedArray<T> { private var array: [T] = [] private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess", attributes: .concurrent) public func append(newElement: T) { self.accessQueue.async(flags:.barrier) { self.array.append(newElement) } } public func removeAtIndex(index: Int) { self.accessQueue.async(flags:.barrier) { self.array.remove(at: index) } } public var count: Int { var count = 0 self.accessQueue.sync { count = self.array.count } return count } public func first() -> T? { var element: T? self.accessQueue.sync { if !self.array.isEmpty { element = self.array[0] } } return element } public subscript(index: Int) -> T { set { self.accessQueue.async(flags:.barrier) { self.array[index] = newValue } } get { var element: T! self.accessQueue.sync { element = self.array[index] } return element } } }
My approach to this problem was using serial dispatch queue, to synchronise access to boxed array. It will block the thread when you try to get the value at index and queue is really busy, but that's the problem with locks as well. public class SynchronizedArray<T> { private var array: [T] = [] private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_SERIAL) public func append(newElement: T) { dispatch_async(self.accessQueue) { self.array.append(newElement) } } public subscript(index: Int) -> T { set { dispatch_async(self.accessQueue) { self.array[index] = newValue } } get { var element: T! dispatch_sync(self.accessQueue) { element = self.array[index] } return element } } } var a = SynchronizedArray<Int>() a.append(1) a.append(2) a.append(3) // can be empty as this is non-thread safe access println(a.array) // thread-safe synchonized access println(a[0]) println(a[1]) println(a[2])
Details Xcode 10.1 (10B61), Swift 4.2 Xcode 10.2.1 (10E1001), Swift 5 Solution import Foundation // https://developer.apple.com/documentation/swift/rangereplaceablecollection struct AtomicArray<T>: RangeReplaceableCollection { typealias Element = T typealias Index = Int typealias SubSequence = AtomicArray<T> typealias Indices = Range<Int> fileprivate var array: Array<T> var startIndex: Int { return array.startIndex } var endIndex: Int { return array.endIndex } var indices: Range<Int> { return array.indices } func index(after i: Int) -> Int { return array.index(after: i) } private var semaphore = DispatchSemaphore(value: 1) fileprivate func _wait() { semaphore.wait() } fileprivate func _signal() { semaphore.signal() } } // MARK: - Instance Methods extension AtomicArray { init<S>(_ elements: S) where S : Sequence, AtomicArray.Element == S.Element { array = Array<S.Element>(elements) } init() { self.init([]) } init(repeating repeatedValue: AtomicArray.Element, count: Int) { let array = Array(repeating: repeatedValue, count: count) self.init(array) } } // MARK: - Instance Methods extension AtomicArray { public mutating func append(_ newElement: AtomicArray.Element) { _wait(); defer { _signal() } array.append(newElement) } public mutating func append<S>(contentsOf newElements: S) where S : Sequence, AtomicArray.Element == S.Element { _wait(); defer { _signal() } array.append(contentsOf: newElements) } func filter(_ isIncluded: (AtomicArray.Element) throws -> Bool) rethrows -> AtomicArray { _wait(); defer { _signal() } let subArray = try array.filter(isIncluded) return AtomicArray(subArray) } public mutating func insert(_ newElement: AtomicArray.Element, at i: AtomicArray.Index) { _wait(); defer { _signal() } array.insert(newElement, at: i) } mutating func insert<S>(contentsOf newElements: S, at i: AtomicArray.Index) where S : Collection, AtomicArray.Element == S.Element { _wait(); defer { _signal() } array.insert(contentsOf: newElements, at: i) } mutating func popLast() -> AtomicArray.Element? { _wait(); defer { _signal() } return array.popLast() } #discardableResult mutating func remove(at i: AtomicArray.Index) -> AtomicArray.Element { _wait(); defer { _signal() } return array.remove(at: i) } mutating func removeAll() { _wait(); defer { _signal() } array.removeAll() } mutating func removeAll(keepingCapacity keepCapacity: Bool) { _wait(); defer { _signal() } array.removeAll() } mutating func removeAll(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) rethrows { _wait(); defer { _signal() } try array.removeAll(where: shouldBeRemoved) } #discardableResult mutating func removeFirst() -> AtomicArray.Element { _wait(); defer { _signal() } return array.removeFirst() } mutating func removeFirst(_ k: Int) { _wait(); defer { _signal() } array.removeFirst(k) } #discardableResult mutating func removeLast() -> AtomicArray.Element { _wait(); defer { _signal() } return array.removeLast() } mutating func removeLast(_ k: Int) { _wait(); defer { _signal() } array.removeLast(k) } #inlinable public func forEach(_ body: (Element) throws -> Void) rethrows { _wait(); defer { _signal() } try array.forEach(body) } mutating func removeFirstIfExist(where shouldBeRemoved: (AtomicArray.Element) throws -> Bool) { _wait(); defer { _signal() } guard let index = try? array.firstIndex(where: shouldBeRemoved) else { return } array.remove(at: index) } mutating func removeSubrange(_ bounds: Range<Int>) { _wait(); defer { _signal() } array.removeSubrange(bounds) } mutating func replaceSubrange<C, R>(_ subrange: R, with newElements: C) where C : Collection, R : RangeExpression, T == C.Element, AtomicArray<Element>.Index == R.Bound { _wait(); defer { _signal() } array.replaceSubrange(subrange, with: newElements) } mutating func reserveCapacity(_ n: Int) { _wait(); defer { _signal() } array.reserveCapacity(n) } public var count: Int { _wait(); defer { _signal() } return array.count } public var isEmpty: Bool { _wait(); defer { _signal() } return array.isEmpty } } // MARK: - Get/Set extension AtomicArray { // Single action func get() -> [T] { _wait(); defer { _signal() } return array } mutating func set(array: [T]) { _wait(); defer { _signal() } self.array = array } // Multy actions mutating func get(closure: ([T])->()) { _wait(); defer { _signal() } closure(array) } mutating func set(closure: ([T]) -> ([T])) { _wait(); defer { _signal() } array = closure(array) } } // MARK: - Subscripts extension AtomicArray { subscript(bounds: Range<AtomicArray.Index>) -> AtomicArray.SubSequence { get { _wait(); defer { _signal() } return AtomicArray(array[bounds]) } } subscript(bounds: AtomicArray.Index) -> AtomicArray.Element { get { _wait(); defer { _signal() } return array[bounds] } set(value) { _wait(); defer { _signal() } array[bounds] = value } } } // MARK: - Operator Functions extension AtomicArray { static func + <Other>(lhs: Other, rhs: AtomicArray) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element { return AtomicArray(lhs + rhs.get()) } static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : Sequence, AtomicArray.Element == Other.Element { return AtomicArray(lhs.get() + rhs) } static func + <Other>(lhs: AtomicArray, rhs: Other) -> AtomicArray where Other : RangeReplaceableCollection, AtomicArray.Element == Other.Element { return AtomicArray(lhs.get() + rhs) } static func + (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> AtomicArray { return AtomicArray(lhs.get() + rhs.get()) } static func += <Other>(lhs: inout AtomicArray, rhs: Other) where Other : Sequence, AtomicArray.Element == Other.Element { lhs._wait(); defer { lhs._signal() } lhs.array += rhs } } // MARK: - CustomStringConvertible extension AtomicArray: CustomStringConvertible { var description: String { _wait(); defer { _signal() } return "\(array)" } } // MARK: - Equatable extension AtomicArray where Element : Equatable { func split(separator: Element, maxSplits: Int, omittingEmptySubsequences: Bool) -> [ArraySlice<Element>] { _wait(); defer { _signal() } return array.split(separator: separator, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } func firstIndex(of element: Element) -> Int? { _wait(); defer { _signal() } return array.firstIndex(of: element) } func lastIndex(of element: Element) -> Int? { _wait(); defer { _signal() } return array.lastIndex(of: element) } func starts<PossiblePrefix>(with possiblePrefix: PossiblePrefix) -> Bool where PossiblePrefix : Sequence, Element == PossiblePrefix.Element { _wait(); defer { _signal() } return array.starts(with: possiblePrefix) } func elementsEqual<OtherSequence>(_ other: OtherSequence) -> Bool where OtherSequence : Sequence, Element == OtherSequence.Element { _wait(); defer { _signal() } return array.elementsEqual(other) } func contains(_ element: Element) -> Bool { _wait(); defer { _signal() } return array.contains(element) } static func != (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool { lhs._wait(); defer { lhs._signal() } rhs._wait(); defer { rhs._signal() } return lhs.array != rhs.array } static func == (lhs: AtomicArray<Element>, rhs: AtomicArray<Element>) -> Bool { lhs._wait(); defer { lhs._signal() } rhs._wait(); defer { rhs._signal() } return lhs.array == rhs.array } } Usage sample 1 import Foundation // init var array = AtomicArray<Int>() print(array) array = AtomicArray(repeating: 0, count: 5) print(array) array = AtomicArray([1,2,3,4,5,6,7,8,9]) print(array) // add array.append(0) print(array) array.append(contentsOf: [5,5,5]) print(array) // filter array = array.filter { $0 < 7 } print(array) // map let strings = array.map { "\($0)" } print(strings) // insert array.insert(99, at: 5) print(array) array.insert(contentsOf: [2, 2, 2], at: 0) print(array) // pop _ = array.popLast() print(array) _ = array.popFirst() print(array) // remove array.removeFirst() print(array) array.removeFirst(3) print(array) array.remove(at: 2) print(array) array.removeLast() print(array) array.removeLast(5) print(array) array.removeAll { $0%2 == 0 } print(array) array = AtomicArray([1,2,3,4,5,6,7,8,9,0]) array.removeSubrange(0...2) print(array) array.replaceSubrange(0...2, with: [0,0,0]) print(array) array.removeAll() print(array) array.set(array: [1,2,3,4,5,6,7,8,9,0]) print(array) // subscript print(array[0]) array[0] = 100 print(array) print(array[1...4]) // operator functions array = [1,2,3] + AtomicArray([4,5,6]) print(array) array = AtomicArray([4,5,6]) + [1,2,3] print(array) array = AtomicArray([1,2,3]) + AtomicArray([4,5,6]) print(array) Usage sample 2 import Foundation var arr = AtomicArray([0,1,2,3,4,5]) for i in 0...1000 { // Single actions DispatchQueue.global(qos: .background).async { usleep(useconds_t(Int.random(in: 100...10000))) let num = i*i arr.append(num) print("arr.append(\(num)), background queue") } DispatchQueue.global(qos: .default).async { usleep(useconds_t(Int.random(in: 100...10000))) arr.append(arr.count) print("arr.append(\(arr.count)), default queue") } // multy actions DispatchQueue.global(qos: .utility).async { arr.set { array -> [Int] in var newArray = array newArray.sort() print("sort(), .utility queue") return newArray } } }
A minor detail: In Swift 3 (at least in Xcode 8 Beta 6), the syntax for queues changed significantly. The important changes to #Kirsteins' answer will be: private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess") txAccessQueue.async() { // Your async code goes here... } txAccessQueue.sync() { // Your sync code goes here... }
Swift-Nio & Vapor Swift For those of you using Swift-Nio (or Vapor Swift which is based on Swift-Nio), there's a built in solution for this problem: class MyClass { let lock = Lock() var myArray: Array<Int> = [] func networkRequestWhatEver() { lock.withLock { array.append(someValue) } } } Note that you should use the same Lock object when modifing the same Array object (or Dictionary, etc.). https://github.com/apple/swift-nio/blob/5e728b57862ce9e13877ff1edc9249adc933070a/Sources/NIOConcurrencyHelpers/lock.swift#L15
Thread-safe Data Structures with Actors As of Swift 5.5 you can express this with an actor: actor SyncArray<T> { private var buffer: [T] init<S: Sequence>(_ elements: S) where S.Element == T { buffer = Array(elements) } var count: Int { buffer.count } func append(_ element: T) { buffer.append(element) } #discardableResult func remove(at index: Int) -> T { buffer.remove(at: index) } } Not only it makes the code simpler and less error prone, but it makes more explicit the potential race condition pointed out in an other answer: Task { let array = SyncArray([1]) if await array.count == 1 { await array.remove(at: 0) } } There are two suspension points here, meaning that by the time .remove(at:) is called, the array count could have changed. Such read-then-write operation must be atomic to be consistent, thus it should be defined as a method on the actor instead: extension SyncArray { func removeLastIfSizeOfOne() { if buffer.count == 1 { buffer.remove(at: 0) } } } Above, the absence of suspension points indicates that the operation is performed atomically. Another solution that works without writing an extension is to use the isolated keyword like this: func removeLastIfSizeOfOne<T>(_ array: isolated SyncArray<T>) { if array == 1 { array(at: 0) } } This will isolate the passed actor for the duration of the whole call instead of at each of its suspension points. Calling this function requires only one suspension point.
Here is the answer for Swift 4, let queue = DispatchQueue(label: "com.readerWriter", qos: .background, attributes: .concurrent) var safeArray: [String] = [] subscript(index: Int) -> String { get { queue.sync { return safeArray[index] } } set(newValue) { queue.async(flags: .barrier) { [weak self] in self?.safeArray[index] = newValue } } }
I think dispatch_barriers are worth looking into. Using gcd for synchronicity is more intuitive to me than using synchronize keyword to avoid state mutation from multiple threads. https://mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html
Approach: Use DispatchQueue to synchronise Refer: http://basememara.com/creating-thread-safe-arrays-in-swift/ Code: Below is a crude implementation of a thread safe array, you can fine tune it. public class ThreadSafeArray<Element> { private var elements : [Element] private let syncQueue = DispatchQueue(label: "Sync Queue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil) public init() { elements = [] } public init(_ newElements: [Element]) { elements = newElements } //MARK: Non-mutating public var first : Element? { return syncQueue.sync { elements.first } } public var last : Element? { return syncQueue.sync { elements.last } } public var count : Int { return syncQueue.sync { elements.count } } public subscript(index: Int) -> Element { get { return syncQueue.sync { elements[index] } } set { syncQueue.sync(flags: .barrier) { elements[index] = newValue } } } public func reversed() -> [Element] { return syncQueue.sync { elements.reversed() } } public func flatMap<T>(_ transform: (Element) throws -> T?) rethrows -> [T] { return try syncQueue.sync { try elements.flatMap(transform) } } public func filter(_ isIncluded: (Element) -> Bool) -> [Element] { return syncQueue.sync { elements.filter(isIncluded) } } //MARK: Mutating public func append(_ element: Element) { syncQueue.sync(flags: .barrier) { elements.append(element) } } public func append<S>(contentsOf newElements: S) where Element == S.Element, S : Sequence { syncQueue.sync(flags: .barrier) { elements.append(contentsOf: newElements) } } public func remove(at index: Int) -> Element? { var element : Element? syncQueue.sync(flags: .barrier) { if elements.startIndex ..< elements.endIndex ~= index { element = elements.remove(at: index) } else { element = nil } } return element } } extension ThreadSafeArray where Element : Equatable { public func index(of element: Element) -> Int? { return syncQueue.sync { elements.index(of: element) } } }
firstly, objc_sync_enter not works objc_sync_enter(array) defer { objc_sync_exit(array) } reason objc_sync_enter / objc_sync_exit not working with DISPATCH_QUEUE_PRIORITY_LOW objc_sync_enter is an extremely low-level primitive, and isn't intended to be used directly. It's an implementation detail of the old #synchronized system in ObjC. for swift, should use like this, just as #Kirsteins said, and I suggest sync instead of async: private let syncQueue = DispatchQueue(label:"com.test.LockQueue") func test(){ self.syncQueue.sync{ // thread safe code here } }
If you want thread-safe interaction with your array, you must synchronize your access. There are many alternatives suggested (and a few that have been omitted), so let us survey the various synchronization alternatives: Serial dispatch queue: This is a straightforward and intuitive GCD pattern. Reader-writer pattern with concurrent queue: This is an elegant refinement of the serial dispatch queue pattern, using concurrent queue with asynchronous “writes” (so the caller does not wait for the write to finish) with a barrier (to prevent any interaction concurrent with a “write”), but it offers concurrent “reads” (allowing greater concurrency during “reads”). This is a sophisticated and appealing pattern, but in practice, it is only useful if the benefits of concurrent “reads” and asynchronous “writes” outweigh the GCD overhead. Locks: NSLock is a fast and simple locking mechanism that is more performant than any of the GCD alternatives for most scenarios: extension NSLocking { func synchronized<T>(_ block: () throws -> T) rethrows -> T { lock() defer { unlock() } return try block() } } os_unfair_lock is another locking mechanism, which is even faster than NSLock, but is a little more complicated to use from Swift. See https://stackoverflow.com/a/66525671/1271826. But in those rare cases where performance is of paramount concern, unfair locks are a compelling solution. The Objective-C objc_sync_enter and objc_sync_exit API: This is not of practical interest in the Swift world. Semaphores: It is conceptually similar to lock-based approaches, but is generally slower than any of the lock-based approaches and can be disregarded in this conversation. Actors: A synchronization mechanism provided by the Swift 5.5 concurrency system. See Protect mutable state with Swift actors. In short, if using async-await, actors are the logical alternative. If not yet adopting the Swift concurrency system, I would gravitate to a lock-based approach (which is simple and fast) or, in rare cases, the GCD reader-writer approach. In practice, the choice of synchronization mechanism is not relevant in most use cases. (And if you are doing so many synchronizations that the performance difference becomes material, you might want to consider how to reduce the number of synchronization points before dwelling on the particular mechanism.) That having been said, the older synchronization mechanisms (semaphores, objc_sync_enter, etc.) simply would not be contemplated anymore. Having outlined the possible synchronization mechanisms, the next question is at what level one performs the synchronization. Specifically, more than once, property wrappers for the entire array have been proposed. This is, invariably, the wrong place to synchronize. The property wrapper approach provides atomic access to the array (which is not quite the same thing as thread-safety), but you generally need a higher level of abstraction. E.g. if one thread is adding elements and while another is reading or removing, you often want each of these high-level tasks to be synchronized, not just the individual accesses of the array.
To improve the accepted answer I would suggest using defer: objc_sync_enter(array) defer { objc_sync_exit(array) } // manipulate the array and the second one func sync(lock: NSObject, closure: () -> Void) { objc_sync_enter(lock) defer { objc_sync_exit(lock) } closure() }
Swift Thread safe collection The main and most common idea of making something(e.g. Collection) thread safe in Swift is: Custom(local) concurrent queue Synchronous reading. Reading a critical section(shared resource) via sync Asynchronous writing with barrier [Swift Thread safe singleton]
There's a great answer here which is threadsafe and doesn't block concurrent reads: https://stackoverflow.com/a/15936959/2050665 It's written in Objective C, but porting to Swift is trivial. #property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue; #property (nonatomic, strong) NSObject *thing; - (id)init { ... _thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT); ... } - (NSObject *)thing { __block NSObject *thing; dispatch_sync(self.thingQueue, ^{ thing = _thing; }); return thing; } - (void)setThing:(NSObject *)thing { dispatch_barrier_async(self.thingQueue, ^{ _thing = thing; }); } Credit to https://stackoverflow.com/users/97337/rob-napier
ArrayType in extension where clause
extension Array where Element: _ArrayType, Element.Generator.Element: Any { func transpose() -> [Element] { if self.isEmpty { return [Element]() } let count = self[0].count var out = [Element](repeating: Element(), count: count) for outer in self { for (index, inner) in outer.enumerated() { out[index].append(inner) } } return out } } I am getting this error in Swift 3.0 after converting it from Swift 2.2. The elements of the array are also array. So how to define it in Swift 3.0?
extension Array where Element : Collection, Element.Index == Int, Element.IndexDistance == Int { func transpose() -> [[Element.Iterator.Element]] { typealias InnerElement = Element.Iterator.Element if self.isEmpty { return [] } let count = self[0].count var out = [[InnerElement]](repeating: [InnerElement](), count: count) for outer in self { for (index, inner) in outer.enumerated() { out[index].append(inner) } } return out } }
Stack implementation in Swift
I'm new to Swift and iOS programming. I'm trying to test out a simple algorithm and need an array of Stacks. Don't have to be anything fancy (Stacks of Ints will do). I got the Stack implementation from The Swift Programming Language documentation: struct IntStack { var items = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } mutating func count() -> Int { return items.count } mutating func show() { println(items) } } The count and show functions are my contribution. But when I try to declare an array of Stacks I get an error... var lines = IntStack()[5] "IntStack" does not have a member named subscript I'm guessing it has something to do with Optionals but can figure out what it is. Any help?
Details Swift 5.1, Xcode 11.3.1 Generic Stack Implementation Stackable protocol protocol Stackable { associatedtype Element func peek() -> Element? mutating func push(_ element: Element) #discardableResult mutating func pop() -> Element? } extension Stackable { var isEmpty: Bool { peek() == nil } } Stack struct Stack<Element>: Stackable where Element: Equatable { private var storage = [Element]() func peek() -> Element? { storage.last } mutating func push(_ element: Element) { storage.append(element) } mutating func pop() -> Element? { storage.popLast() } } extension Stack: Equatable { static func == (lhs: Stack<Element>, rhs: Stack<Element>) -> Bool { lhs.storage == rhs.storage } } extension Stack: CustomStringConvertible { var description: String { "\(storage)" } } extension Stack: ExpressibleByArrayLiteral { init(arrayLiteral elements: Self.Element...) { storage = elements } } Usage var stack = Stack<Int>() stack.push(1) stack.push(2) stack.push(3) print(stack.peek()) print(stack.pop()) print(stack) print(stack == Stack<Int>()) stack = [3,2,1] print(stack)
There's no problem with what you're doing there - that's just not the syntax for declaring an array. If you want an array of 5 stacks, you can do this: [IntStack(), IntStack(), IntStack(), IntStack(), IntStack()] Or, you can initialise the array like this: Array(count: 5, repeatedValue: IntStack()) Also, you don't need to mark your functions as mutating unless they actually mutate the structure - so count() and show() don't need it.
It's possible to just extend arrays with stack specific methods. This might or might not be what you want, depending on if you want to disallow array like access. protocol Stack { associatedtype Element mutating func push(item: Element) // allows discarding the result without generating a warning. #discardableResult mutating func pop() -> Element? func peek() -> Element? var count: Int { get } } extension Array: Stack { mutating func push(item: Element) { self.append(item) } mutating func pop() -> Element? { if let last = self.last { self.remove(at: self.count - 1) return last } return .none } func peek() -> Element? { self.last } } Simple test case: class StackTests: XCTestCase { func testExample() throws { var stack = Array<Int>() XCTAssertEqual(stack.peek(), .none, "stack is empty, peek returns none") XCTAssertEqual(stack.pop(), .none, "stack is empty, pop returns none") stack.push(item: 0) stack.push(item: 1) stack.push(item: 2) XCTAssertEqual(stack.peek(), 2) XCTAssertEqual(stack.pop(), 2) XCTAssertEqual(stack.peek(), 1) XCTAssertEqual(stack.pop(), 1) XCTAssertEqual(stack.peek(), 0) XCTAssertEqual(stack.pop(), 0) } }
There is no need to declare the size of the stack when you init it. Jus calling this should be enough. var lines = IntStack() Also note that your count() and show() methods should not be mutating since they don't modify the struct in any way.
Just look into this code. Stack example with generic data type and without using the array. class Node<T>: CustomStringConvertible { let value: T var next: Node? var description: String { guard let next = next else { return "\(value)" } return "\(value)\n" + String(describing: next) } init(value: T) { self.value = value } } // Stack class to hold all items class Stack<T>: CustomStringConvertible { var top: Node<T>? var description: String { guard let top = top else { return "---- Stack is EMPTY ----" } return "---- Stack Begin ----\n" + String(describing: top) + "\n---- Stack End ----" } // push func push(_ value: T) { let currentTop = top top = Node(value: value) top?.next = currentTop } #discardableResult func pop() -> T? { let currentTop = top top = top?.next return currentTop?.value } #discardableResult func peek() -> T? { return top?.value } }
Excellent implementation! One thought: I think it should be: func peek() -> Element? { storage.last }
Here is a Stack implementation using Swift Generics, struct Fruit { let fruitName : String let color : String init(_ name: String,_ color: String) { self.fruitName = name self.color = color } } let fruit1 = Fruit("Apple", "Red") let fruit2 = Fruit("Grapes", "Green") let fruitStack = Stack<Fruit>() fruitStack.push(fruit1) fruitStack.push(fruit2) let fruitFfromStack = fruitStack.pop() print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack?.fruitName)) ,Color : \(String(describing: fruitFfromStack?.color))") let fruitFfromStack1 = fruitStack.pop() print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack1?.fruitName)) ,Color : \(String(describing: fruitFfromStack1?.color))") Full code is here : https://reactcodes.blogspot.com/2019/01/generic-stack-implementation-with.html
Queue implementation in Swift language
I m trying to implement Queue collection type in Swift platform. I have got some problems about peek, poll and offer functions. When I try to use these functions in my code, it fails. Do you have any advice or true algorithm for that? import Foundation class Node<T> { var value: T? = nil var next: Node<T>? = nil var prev: Node<T>? = nil init() { } init(value: T) { self.value = value } } class Queue<T> { var count: Int = 0 var head: Node<T> = Node<T>() var tail: Node<T> = Node<T>() var currentNode : Node<T> = Node<T>() init() { } func isEmpty() -> Bool { return self.count == 0 } func next(index:Int) -> T? { if isEmpty() { return nil } else if self.count == 1 { var temp: Node<T> = currentNode return temp.value } else if index == self.count{ return currentNode.value }else { var temp: Node<T> = currentNode currentNode = currentNode.next! return temp.value } } func setCurrentNode(){ currentNode = head } func enQueue(key: T) { var node = Node<T>(value: key) if self.isEmpty() { self.head = node self.tail = node } else { node.next = self.head self.head.prev = node self.head = node } self.count++ } func deQueue() -> T? { if self.isEmpty() { return nil } else if self.count == 1 { var temp: Node<T> = self.tail self.count-- return temp.value } else { var temp: Node<T> = self.tail self.tail = self.tail.prev! self.count-- return temp.value } } //retrieve the top most item func peek() -> T? { if isEmpty() { return nil } return head.value! } func poll() -> T? { if isEmpty() { return nil }else{ var temp:T = head.value! deQueue() return temp } } func offer(var key:T)->Bool{ var status:Bool = false; self.enQueue(key) status = true return status } }
Aside from the bugs, there are a couple of things about your implementation that you probably want to change to make it more Swift-like. One is it looks like you're replicating the Java names like poll and offer – these names are (IMHO) a little strange, and partly related to needing to have two functions, an exception-throwing version and a non-exception version. Since Swift doesn't have exceptions, you can probably just name them using the conventional names other Swift collections use, like append. The other issue is that your implementation incorporates traversing the queue into the queue itself. It's better to do this kind of traversal outside the collection than mix the two. Swift collections do this with indexes. Here's a possible Swift-like queue implementation. First, the node and base queue definition: // singly rather than doubly linked list implementation // private, as users of Queue never use this directly private final class QueueNode<T> { // note, not optional – every node has a value var value: T // but the last node doesn't have a next var next: QueueNode<T>? = nil init(value: T) { self.value = value } } // Ideally, Queue would be a struct with value semantics but // I'll leave that for now public final class Queue<T> { // note, these are both optionals, to handle // an empty queue private var head: QueueNode<T>? = nil private var tail: QueueNode<T>? = nil public init() { } } Then, extend with an append and dequeue method: extension Queue { // append is the standard name in Swift for this operation public func append(newElement: T) { let oldTail = tail self.tail = QueueNode(value: newElement) if head == nil { head = tail } else { oldTail?.next = self.tail } } public func dequeue() -> T? { if let head = self.head { self.head = head.next if head.next == nil { tail = nil } return head.value } else { return nil } } } At this point, you're almost done if all you want to do is add and remove. To add traversal, first create an index type, which is a simple wrapper on the node type: public struct QueueIndex<T>: ForwardIndexType { private let node: QueueNode<T>? public func successor() -> QueueIndex<T> { return QueueIndex(node: node?.next) } } public func ==<T>(lhs: QueueIndex<T>, rhs: QueueIndex<T>) -> Bool { return lhs.node === rhs.node } Then, use this index to conform to MutableCollectionType: extension Queue: MutableCollectionType { public typealias Index = QueueIndex<T> public var startIndex: Index { return Index(node: head) } public var endIndex: Index { return Index(node: nil) } public subscript(idx: Index) -> T { get { precondition(idx.node != nil, "Attempt to subscript out of bounds") return idx.node!.value } set(newValue) { precondition(idx.node != nil, "Attempt to subscript out of bounds") idx.node!.value = newValue } } typealias Generator = IndexingGenerator<Queue> public func generate() -> Generator { return Generator(self) } } From conforming to collection type, you get a whole load of stuff for free: var q = Queue<String>() q.append("one") q.append("two") for x in q { println(x) } isEmpty(q) // returns false first(q) // returns Optional("one") count(q) // returns 2 ",".join(q) // returns "one,two" let x = find(q, "two") // returns index of second entry let counts = map(q) { count($0) } // returns [3,3] Finally, there's 3 more protocols that are good to conform to: ExtensibleCollectionType, Printable and ArrayLiteralConvertible: // init() and append() requirements are already covered extension Queue: ExtensibleCollectionType { public func reserveCapacity(n: Index.Distance) { // do nothing } public func extend<S : SequenceType where S.Generator.Element == T> (newElements: S) { for x in newElements { self.append(x) } } } extension Queue: ArrayLiteralConvertible { public convenience init(arrayLiteral elements: T...) { self.init() // conformance to ExtensibleCollectionType makes this easy self.extend(elements) } } extension Queue: Printable { // pretty easy given conformance to CollectionType public var description: String { return "[" + ", ".join(map(self,toString)) + "]" } } These mean you can now create queues as easily arrays or sets: var q: Queue = [1,2,3] println(q) // prints [1, 2, 3]
There are a lot of little issues regarding the internal consistency of your model: When you first instantiate a new Queue, you are initializing head, tail and current to three different Node objects (even though nothing's been queued yet!). That doesn't make sense. Personally, I'd be inclined to make those three properties optional and leave them as nil until you start enqueuing stuff. By the way, when you start using optionals for these properties, many of the other methods are simplified. It looks like you're trying to implement a doubly linked list. So, when you dequeue, you need to not only update the Queue properties, but you also need to update the next pointer for the next item that will be dequeued (because it still will be pointing to that item you already dequeued). You don't want your linked list maintaining references to objects that have been dequeued and should be removed. When you dequeue the last item, you really should be clearing out head and tail references. You're implementing a doubly linked list, without regard to the object ownership model. Thus, as soon as you have more than one item in your list, you've got a strong reference cycle between nodes and if not remedied, this will leak if there are still objects in the queue when the queue, itself, is deallocated. Consider making one of the references weak or unowned. I'd suggest keeping this simple (just enqueue and dequeue). The concept of poll and offer may make sense in terms of an arbitrary linked list, but not in the context of a queue. The implementations of poll and offer are also incorrect (e.g. poll calls deQueue which removes the tail, but the object you return is the head!), but I presume you'd just remove these functions altogether. Likewise, I do not understand the intent of current in the context of a queue. I'd suggest you make Queue and Node conform to Printable. It will simplify your debugging process.
The following is code of a playground consisting of a queue implemented with an array and a queue implemented with nodes. There are substantial performance differences between the two but if you going to be iterating through a queue you might want to use one with an array. import UIKit // for NSDate() used in testing) // QUEUE WITH ARRAY IMPLEMENTATION (For ease of adaptibility, slow enque, faster deque): struct QueueArray<T> { private var items = [T]() mutating func enQueue(item: T) { items.append(item) } mutating func deQueue() -> T? { return items.removeFirst() } func isEmpty() -> Bool { return items.isEmpty } func peek() -> T? { return items.first } } // QUEUE WITH NODE IMPLEMENTATION (For performance, if all you need is a queue this is it): class QNode<T> { var value: T var next: QNode? init(item:T) { value = item } } struct Queue<T> { private var top: QNode<T>! private var bottom: QNode<T>! init() { top = nil bottom = nil } mutating func enQueue(item: T) { let newNode:QNode<T> = QNode(item: item) if top == nil { top = newNode bottom = top return } bottom.next = newNode bottom = newNode } mutating func deQueue() -> T? { let topItem: T? = top?.value if topItem == nil { return nil } if let nextItem = top.next { top = nextItem } else { top = nil bottom = nil } return topItem } func isEmpty() -> Bool { return top == nil ? true : false } func peek() -> T? { return top?.value } } // QUEUE NODES TEST let testAmount = 100 var queueNodes = Queue<Int>() let queueNodesEnqueStart = NSDate() for i in 0...testAmount { queueNodes.enQueue(i) } let queueNodesEnqueEnd = NSDate() while !queueNodes.isEmpty() { queueNodes.deQueue() } let queueNodesDequeEnd = NSDate() // QUEUE ARRAY TEST var queueArray = QueueArray<Int>() let queueArrayEnqueStart = NSDate() for i in 0...testAmount { queueArray.enQueue(i) } let queueArrayEnqueEnd = NSDate() while !queueArray.isEmpty() { queueArray.deQueue() } let queueArrayDequeEnd = NSDate() // QUEUE NODES RESULT: print("queueEnqueDuration: \(queueNodesEnqueEnd.timeIntervalSinceDate(queueNodesEnqueStart)), Deque: \(queueNodesDequeEnd.timeIntervalSinceDate(queueNodesEnqueEnd))") // QUEUE ARRAY RESULT: print("queueArrayEnqueDuration: \(queueArrayEnqueEnd.timeIntervalSinceDate(queueArrayEnqueStart)), Deque: \(queueArrayDequeEnd.timeIntervalSinceDate(queueArrayEnqueEnd))")
Queue with Array struct Queue<T> { private var list = [T]() var isEmpty: Bool { return self.list.isEmpty } var front: T? { return self.list.first } mutating func enqueue(_ item: T) { self.list.append(item) } mutating func dequeue() -> T? { guard self.isEmpty == false else { return nil } return self.list.removeFirst() } }
Swift 4 simple Stack for any type; string, int, array, etc. struct Stack<Element> { var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } mutating func peek() -> Element { return items.last! } mutating func pushFirst(_ item: Element) { items.insert(item, at: 0) } } example with strings: let names = ["Bob", "Sam", "Sue", "Greg", "Brian", "Dave"] //create stack of string type var stackOfStrings = Stack<String>() //add to bottom of stack for stringName in names { stackOfStrings.push(stringName) } //print and remove from stack for stringName in names { print(stringName) stackOfStrings.pop(stringName) } //add to top of stack for stringName in names { stackOfStrings.pushFirst(stringName) } //look at item in stack without pop for stringName in names { //see what Top item is without remove let whatIsTopItem = stackOfStrings.peek(stringName) if whatIsTopItem == "Bob" { print("Best friend Bob is in town!") } } //stack size let stackCount = stackOfStrings.items.count more info here: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html