/ iOS

weak or unowned?

In Swift, we often use weak or unowned to break reference cycles for closures. I use unowned a lot because I don't have to handle optinal type. I love concise code. For example:

class ViewController: UIViewController {
    lazy var api: API = {
        let api = API()
        api.completionHandler = { [unowned self] obj in
            self.doSomething()
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        api.request()
    }
}

While I know it's safer to use weak, everthing seems OK. Then I got some mysterious crashes.

SIGABRT
0 libsystem_kernel.dylib  __pthread_kill + 8
1 libsystem_pthread.dylib _pthread_kill$VARIANT$mp + 376
2 libsystem_c.dylib abort + 140
3 libswiftCore.dylib  swift::warning(unsigned int, char const*, ...) + 0
4 libswiftCore.dylib  swift::swift_abortRetainUnowned(void const*) + 32
5 libswiftCore.dylib  swift_unknownUnownedTakeStrong + 0

It's not obvious what's wrong until I did a quick search and read this. So it's not safe to use unowned for an asynchronously executed closure. ViewController may be deallocated before the api response return.

I was frustrated, it seems stupid for me to let this happen when I can avoid it (luckily it was fixed in alpha release). I'll be more cautious when I use unowned next time.

Also, it made me think more broadly about the way I treat defensive programming. I always put conciseness before safety unintentionally without knowing the hidden danger it brings. While conciseness is good, it's not worth it if your code become fragile and easy to crash.

weak or unowned?
Share this