Swift ARC and blocks

2019-02-17 21:14发布

问题:

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:

[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)
}