Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2017-05-02

Optionals and weak references | Swift gotcha

Thanks to the swift user list I became aware of the following gotcha that can lead to runtime errors of the "unexpectedly nil" kind.

The problem is as follows:

First optionals, when using optionals the following is totally safe:

var a: Int?
if a != nil { a! = a! + 1 }

Before using 'a' it is tested on non-nil and then used by force-unwrap.

No problem there.

But consider the following with weak references:


class C {
    var a: Int = 0
}

var c: C?

let b = {
    [weak c] () -> Int in
    if c != nil { return c!.a + 1 }
    return 0
}


This may bomb at runtime. It will often work quite alright, but sometimes it may crash your app. If your luck runs like Murphy's, the first crash will come right after you released the app... And you will be quite unable to reproduce it.

The problem here is that in between the test for non-nil and the usage of 'c' itself, 'c' may have become nil.

This problems only occurs in multithreading applications, which is to say in (almost?) all of them. It happens when one thread nils the referenced variable and another thread is using that variable.

While there are situations where this will work correctly, the guiding principle should be:

Never force unwrap a weak reference.

First create a strong reference to it, then access it through the strong reference.

Like this:

class C {
    var a: Int = 0
}

var c: C?

let b = {
    [weak c] () -> Int in
    guard let c = c else { return 0 }
    return c.a + 1

}

Quick tip: if [weak self] is used, then use back-ticks on self, like this:


    [weak self] () -> Int in
    guard let `self` = self else { return 0 }


Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.