Thread Safety In IOS — Swift

Mohit Bhalla
2 min readMay 6, 2018

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 that 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 an ordered collection of a 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

Principle Engineer iOS, Wynk, Airtel | ex Hindustan times