6

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.

Community
  • 1
  • 1
Wak
  • 818
  • 2
  • 11
  • 18
  • 2
    From [The Swift Programming Language](https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html): "If you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error.” – Rob Aug 12 '14 at 01:18
  • 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 Aug 12 '14 at 01:20
  • 2
    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 Aug 12 '14 at 14:04
  • @RobNapier it's not that it doesn't crash, but it also prints the pointer value, it's not nil. – Wak Aug 12 '14 at 19:25
  • " 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 Sep 20 '14 at 20:59
  • @RobNapier - weak answer. But I like it. ;-) – clearlight Jan 28 '15 at 20:32

1 Answers1

9

[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)
}
drewag
  • 93,393
  • 28
  • 139
  • 128
  • Thanks. It's not all my code, I just copied the interesting part. What you said, makes sense, but why does it works on Objc? – Wak Aug 12 '14 at 01:06
  • @Wak I updated my answer, but weak works in Objective-C silently because you can send messages to `nil` in Objective-C – drewag Aug 12 '14 at 01:09
  • It doesn't only compile, but it prints the object pointer, and it's not nil (On ObjC) – Wak Aug 12 '14 at 01:15
  • @Wak something is keeping a strong reference to it in your ObjC version then – drewag Aug 12 '14 at 01:16
  • It's the exact same case as on Swift. On a empty project viewcontroller's viewDidLoad, just add the block of code I copied here, nothing else. It crashes on Swift but works on ObjC. – Wak Aug 12 '14 at 01:18
  • 1
    @Wak, I cannot say for certain what the difference might be. It is probably just a race condition. However, my description of `weak` v.s. `unowned` / `unsafe unretained` v.s. `strong` is 100% accurate. The important thing is whether or not removing the `[weak self] in` in Swift fixes your crash. – drewag Aug 12 '14 at 01:20
  • It does fix my crash, but I still don't understand why it works on Objc and not on swift. Even if it's a race condition that I don't think it is, why it only happens on swift? It's frustrating. Thanks anyway. – Wak Aug 12 '14 at 01:23
  • @wak, the truth is that it should not work in ObjC either. It is a fluke that the reference is still around in ObjC, not the other way around. – drewag Aug 12 '14 at 01:27
  • I've edited my post with more info of what I found out. There are more differences on weak/unowned than just nilling. – Wak Aug 12 '14 at 13:44
  • 1
    There is no `unowned` in ObjC, so it's not clear what you mean when you say it works there. `weak` should not crash in either; nor should `strong`. – Rob Napier Aug 12 '14 at 14:07
  • 1
    @RobNapier in objective-c, unowned is called "unsafe unretained". It does exist, under a different name – drewag Aug 12 '14 at 14:52
  • @Wak, the reason that the compiler doesn't complain about your usage of weak is that you can still print an optional that lacks a value. It is still potentially setting it to nil. Bottom line, I don't know why your code is crashing or not crashing as I can't see all the code, but your code is doing incorrect memory management. You should only use `weak` or `unowned` in cases where there are circular references. You may have a multithreading issue, you might have a race condition, you might just have an error somewhere else that is related. – drewag Aug 12 '14 at 15:03
  • @RobNapier, http://stackoverflow.com/questions/8592289/arc-the-meaning-of-unsafe-unretained – drewag Aug 12 '14 at 15:05
  • @drewag ignore "other code" possibilities, I edited my message to make it clear. It's an empty project with this implementation on viewDidLoad. You can try by yourself and see that there's nothing else involved. You can discard the "incorrect memory management" argument for this. Also, on the weak example, it doesn't set to nil, it prints the pointer and I can inspect using the debugger. It's not nil – Wak Aug 12 '14 at 19:27
  • "In Objective-C, `unowned` is called `unsafe unretained`." No it isn't. Using an `unowned` reference in Swift when the object is deallocated is guaranteed to cause a runtime crash by the Swift language specification. Using an `unsafe_unretained` reference in Objective-C after the object is deallocated invokes undefined behavior. – user102008 Sep 20 '14 at 20:55
  • "unowned ... means that it will not be set to nil for you" It will be internally marked as invalid somehow for you, so that when you try to use it, it can be guaranteed to produce a runtime error. – user102008 Sep 20 '14 at 21:21
  • @drewag Why do you think, it's best to use a strong reference? The user might leave the ViewController before the possibly long-term async operation finishes. The async operation would hold strong reference to invisible ViewController ... I am right? – stevo.mit Jun 18 '15 at 15:37
  • @stevo.mit It depends on if you will still want to do something with the view controller when the async operation finishes (odds are yes if you are referencing it in the completion block). – drewag Jun 19 '15 at 05:01
  • @drewag But one usually wants to do something with the view controller only if it is still visible. I can't see the point in updating the controller that the user left before the async task finished. Thats way i thought that [weak self] would do the job so the controller can be released from the memory as soon as user navigates away from it. Have a look at my question: http://stackoverflow.com/questions/30920576/swift-closures-weak-self-and-async-tasks/30922763#30922763 – stevo.mit Jun 19 '15 at 05:54