> On Aug 30, 2017, at 7:02 PM, Yvo van Beek <y...@yvo.net> wrote: > > Hi John, > > I see that I've used DispatchQueue.main in my example which is probably a > poor choice to demonstrate the issue: > > class MyClass { > let queue = DispatchQueue(label: "MyApp.MyQueue") > > func start() { > queue.async { > otherClass.doSomethingThatTakesAWhile() > } > > ... > > queue.async { > self.doSomething() > } > } > } > > This would create a retain cycle wouldn't it?
You're correct that there's a temporary cycle which lasts until the queue executes the closure. However, temporary cycles like this rarely cause memory leaks for the same reason that local variables rarely cause memory leaks: eventually the closure will be executed or the function will return. The only way that a closure on a dispatch queue can cause a memory leak is if it constantly enqueues new closures that recreate the same cycle. If you're doing a dispatch with a very substantial delay (in the hundreds of milliseconds), it can still be a good idea to use a weak reference just so objects can be collected faster. But it's not strictly necessary just to avoid leaks. John. > > - Yvo > > > On Wed, Aug 30, 2017 at 6:48 PM, John McCall <rjmcc...@apple.com > <mailto:rjmcc...@apple.com>> wrote: > >> On Aug 30, 2017, at 6:45 PM, Yvo van Beek via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >> When I'm writing code I like it to be free from any distractions that aren't >> really relevant to the problem that I'm trying to solve. One of these >> distractions is having to pay a lot of attention to retain cycles. As my >> code grows, I start making extensions to simplify my code. >> >> I've created the following helper for DispatchQueues: >> >> extension DispatchQueue { >> func async<T: AnyObject>(weak arg: T, execute: @escaping (T) -> Void) { >> async { [weak arg] in >> if let argRef = arg { execute(argRef) } >> } >> } >> } >> >> It allows you to do this: >> >> DispatchQueue.main.async(weak: self) { me in >> me.updateSomePartOfUI() >> } >> > > Closures handed off to dispatch queues will not cause retain cycles. > > John. > >> When functions are passed as a closure, the compiler won't warn about a >> possible retain cycle (there is no need to prefix with self). That's why >> I've also created helpers for calling instance functions: >> >> func blockFor<Target: AnyObject>(_ target: Target, method: @escaping >> (Target) -> () -> Void) -> () -> Void { >> return { [weak target] in >> if let targetRef = target { method(targetRef)() } >> } >> } >> >> func blockFor<Target: AnyObject, Args>(_ target: Target, method: @escaping >> (Target) -> (Args) -> Void, args: Args) -> () -> Void { >> return { [weak target] in >> if let targetRef = target { method(targetRef)(args) } >> } >> } >> >> Calls look like this: >> >> class MyClass { >> func start() { >> performAction(completion: blockFor(self, method: MyClass.done)) >> } >> >> func done() { >> ... >> } >> } >> >> When you look at code samples online or when I'm reviewing code of >> colleagues this seems a real issue. A lot of people probably aren't aware of >> the vast amounts of memory that will never be released (until their apps >> start crashing). I see people just adding self. to silence the complier :( >> >> I'm wondering what can be done to make this easier for developers. Maybe >> introduce a 'guard' keyword for closures which skips the whole closure if >> the instances aren't around anymore. Since guard is a new keyword in this >> context it shouldn't break any code? >> >> DispatchQueue.main.async { [guard self] in >> self.updateSomePartOfUI() >> } >> >> I don't have any ideas yet for a better way to pass functions as closures. >> >> - Yvo >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution