Created
June 10, 2014 16:55
-
-
Save jstn/0dedc76b287af09d1ddb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// JSTN / 10 June 2014 | |
// I really like Swift so far, but I can't help be a little sad that I still find | |
// myself doing the weakSelf/strongSelf dance to avoid retain cycles. | |
// For a contrived example, suppose we had a class like this with a queue: | |
import Foundation | |
class ParallelMessenger { | |
let queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT) | |
func message(text: String) { | |
dispatch_async(queue) { | |
NSLog(text, nil) | |
} | |
} | |
// Now suppose we wanted to count every message in a thread-safe way: | |
var messageCount = 0 | |
func messageAndCount(text: String) { | |
// We'll need to refer to self a couple times here, but we don't want | |
// any messages to get logged if self has been deallocated by the | |
// time the block executes. Swift has a nice syntax that allows you | |
// to make any references to self within a closure automatically weak: | |
dispatch_async(queue) { [weak self] in | |
// So self is now a weak reference, meaning it becomes nil if self | |
// gets deallocated. Since we're on a private queue, it's possible | |
// for self to disappear at any moment, so to keep working with it | |
// we need to a create a strong reference: | |
if let strongSelf = self { | |
NSLog(text, nil) | |
// We can't increment strongSelf.messageCount because we're on a | |
// concurrent queue and can't risk memory contention. Instead we | |
// can dispatch a barrier block, which will execute serially as | |
// soon as any concurrently running blocks finish. | |
// Here again we need the same weak reference behavior, only now | |
// the syntax makes less sense because we'd wind up with a | |
// weak reference to something called strongSelf. So let's | |
// do it manually, not that's it much prettier. Ugh. | |
weak var weakSelf = strongSelf | |
dispatch_barrier_async(strongSelf.queue) { | |
if let strongSelf = weakSelf { | |
strongSelf.messageCount++ // Finally! | |
} | |
} | |
} | |
} | |
} | |
} | |
// In some class designs this actually isn't the behavior you want, like if you | |
// needed to perform some task regardless of whether self still exists (such as | |
// closing a file descriptor). Again, this is a contrived example. | |
// Still, I find myself doing this enough that I wish there was a more concise | |
// way to express it, and without variables called "weakSelf" and "strongSelf", | |
// which seem at odds with the safely typed nature of Swift. | |
// Maybe something like this: | |
// dispatch_async(queue) { [autoweak self] in ... } | |
// Meaning, "make a weak reference to self that is safe to use (i.e. strong) | |
// within the current scope." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment