6
votes

I'm trying a simple example as seen here: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_88

And this is my code. (Ignore other possible code, this is a empty project with this code written inside an empty UIViewcontroller viewDidLoad)

    dispatch_async(dispatch_get_main_queue()) {
        [unowned self] in
        println(self)
    }

I don't understand why it crashes when I run the pro

  • thread #1: tid = 0x1a796, 0x00284d18 libswiftCore.dylib`_swift_release_slow + 8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x458bc681)

Did something changed on the latest beta(5) and this is not supported anymore? Thanks

edit: Interesting that this code works on Objc

__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"%@", weakSelf);
});

edit2: The explanation on this link : Shall we always use [unowned self] inside closure in Swift on the difference of weak and unowned is wrong.

It's not just that weak nils and unowned doesn't. If that's the case, this should crash as well:

  dispatch_async(dispatch_get_main_queue()) {
            [weak self] in
            println(self)
        }

but it doesn't, and it prints the pointer, so, it's not nil.

1
From The Swift Programming Language: "If you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error.” - Rob
Unowned means that self is not retained, but if self is deallocated and the unowned is used then you will get a crash. If it may get deallocated then either use strong or weak. - SomeGuy
Your last comment that [weak self] should lead to a crash isn't correct. self in that case is an Optional. You should expect the above to print nil or something similar. unowned means "I swear it will not be nil, and if it is, crash me." weak means "it's Optional, so nil is acceptable." - Rob Napier
@RobNapier it's not that it doesn't crash, but it also prints the pointer value, it's not nil. - Wak
" The explanation on this link : Shall we always use [unowned self] inside closure in Swift on the difference of weak and unowned is wrong." How is it wrong? - user102008

1 Answers

9
votes

[Unowned self] makes it so the closure does not create a strong reference to self and it does not automatically set it to nil if it gets deallocated either. By the time the async method is executed, self has been deallocated. That is why you are getting the crash.

It certainly doesn't make sense to use unowned in a one time asynchronous call. It would be better to capture a strong reference to it to be sure it sticks around. There still won't be a strong reference cycle because self does not own the closure.

Side Note: This cannot be all of your code as self isn't defined anywhere in your code.

unowned and weak are two different things. In Objective-C, unowned is called unsafe unretained. You can use weak in both languages. weak means that the runtime will automatically convert the reference to nil if the object is deallocated. unowned or unsafe unretained means that it will not be set to nil for you (which is why it is called "unsafe" in Objective-C.

Unowned should only ever be used in circumstances where the object will never be deallocated. In those circumstances, use weak.

Keep in mind, that if you capture a variable as weak in Swift, the reference will be made an optional so to use it you will have to unwrap it:

dispatch_async(dispatch_get_main_queue()) {
    [weak self] in
    if let actualSelf == self {
         // do something with actualSelf
    }
    // you can still print the "wrapped" self because it is fine to print optionals
    // even if they are `nil`
    println(self)
}

But to be clear, it would still be best to use a strong reference in this circumstance:

dispatch_async(dispatch_get_main_queue()) {
    println(self)
}