Thread Safety In IOS — Swift

Mohit Bhalla
May 6, 2018 · 2 min read

Hi Guys, here are my findings on which types in swift are not thread safe and which are thread safe.

(Almost) nothing in Swift is intrinsically threadsafe

  1. not references,
  2. not weak references,
  3. not arrays,
  4. not strings
  5. nor any other mutable value.

If you want write/read or write/write access to anything from two threads, you must use locks to ensure safety.

Things which are thread safe

  1. read/read is safe from multiple threads in most cases.

2. Technically, there are two minor features that are intrinsically threadsafe:

  1. the “retain count” of a reference (not the reference itself) is threadsafe
  2. Globals and static variables are also initialized in a threadsafe manner.

Arrays:

An array is a ordered collection of similar type of value. The same value can appear in an array multiple times at different positions.

How Swift Array works — (copy-to-write)

The way Swift arrays work is that they are values, but they don’t store their data directly. There is a reference-type buffer that copies of the same Array instance share.

When you mutate (for example, by appending), it uses the standard library function ‘isUniquelyReferenced’ to see if there are any other Arrays pointing to the buffer it’s about to append to. If there are, it makes a copy and the copy becomes its new backing store. This is called ‘copy-to-write’.

How to make Array thread safe:

  1. To read array content : Access it from serial queue in sync mode:

let queue = Dispatch_Queue(label: “myQueue”)

queue.sync{

//use here

}

2. To update Array content: In asyc mode and serial queue -

let queue = Dispatch_Queue(label: “myQueue”)

queue.async(flag:barrier){

//append or remove array here

}

example :

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
}
}
}

Happy coding and keep sharing :)

Mohit Bhalla

Written by

iOS Developer, Daffodil Software Limited

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade