Whoa, hang on. I think it's a jump to say [unowned self] is safer than [strong self], and [weak self] + guard + return definitely isn't safer because it leads to silently ignoring results (and silently ignoring failures).
I'm really curious what cases you all are using [weak self] with so much that you want sugar for it. [unowned self] I get because you want to avoid reference cycles, but [weak self] implies that self might go away before the callback finishes, and, like, shouldn't you know if that's going to happen?
EDIT: [strong self] has benefits for a default because it's consistent with the behavior for structs that contain references.
Again, animation completion handlers come to mind. The main body of the animation is fine with self unowned as it executes immediately, but the completion closure may occur after some user interaction has caused UIKit to discard the view before the animation completes and so you need a weakly captured self there afaik.
One example from a current project is AVPlayer.addPeriodicTimeObserver. And really, any time you're doing something in another thread. Network calls, disk saving operations, etc.
After 1 too many instances where I ended up with a dereferenced Object, now I generally tend use weak instead of unowned since AFAIK it's always safe. Though admittedly I may not understand the semantics completely.
With animation completions it should be okay to strongly capture self, no? The completion closure has a short lifetime (slightly longer than that of the animation itself) and should be discarded immediately after it has been called. Why do you need weak self?
Personally, I've worked on codebases with rules (out of my own control) of the form "always capture self weakly to avoid the possibility of creating reference cycles." Not sure that questionable style guide decisions are good motivation for new features/sugar, though.
It obviously depends on the case but 90% of async stuff happening in an app screen has this problem. The screen (self aka VC or VM or whatever) may go away at any point and operations may finish after. In some apis callbacks will still be called (for example giving you a cancellation callback) and thus weak self is the safer bet. In that case guard self is fine, silently ignoring is what you want.
Happy to be re-educated here, but here's my understanding:
Say we have a UIView with a UIViewPropertyAnimator:
class MyView: UIView {
...
var propertyAnimator: UIViewPropertyAnimator?
...
}
At some point, due to some event, we want to animate some properties on that view and do some cleanup so we have:
class MyView: UIView {
func performImpressiveAnimation() {
let animator = UIViewPropertyAnimator(duration: 1, timingParameters: UISpringTimingParameters())
animator.addAnimations {
self.myFactoredOutAnimationInstanceMethod() // strongly held self, retain cycle
}
animator.addCompletion { _ in
self.myPostAnimationCleanupInstanceMethod() // strongly held self, retain cycle
}
animator.startAnimation()
self.propertyAnimator = animator // retain the property animator or no animations
}
}
If we don't retain the property animator in this situation – the animations don't happen. So we make it an instance property on our UIView.
Therefore when we add the animation blocks and completion handler we have a retain cycle via: self -> animator -> animationBlock -> self.
We need a capture list for our closures.
For the addAnimations(_:)call we're OK with an unowned self – our instance always kicks off the animation so we can guarantee its safety. For the addCompletion(_:) call we need to use weakly as the view may be removed through some user/system event and deallocated prior to the animation block completing and an unowned self would yield a crash.
Unowned is not good default, agreed. That was my mistake.
I guess between strong and weak, it's question of balance. With strong you don't lose the reference and then you don't get crashes. With weak you might, especially if you force it, but usually you have the self?.foo, i.e. question marks to take care of it (and makes programmer knowledgeable about the issue). With weak you break most, if not all reference cycles, so you're not burning memory, whereas currently with strong it's given that your program will have one or more closure reference cycles unless you explicitly do the weak dance yourself (and you have to know about it).
At least for me, the default in closures is almost always that the (view) controller outlives the lifetime of the closure (e.g. a closure running on button click). So the weak reference to self will always be valid when it needs to, but also will not retain the closure in memory when controller goes away. so ARC does the right thing automatically, instead of me having to jump into manual memory management mode.
If you take a look at github repos and just to try find:
guard let strongSelf = self else { return }
guard let `self` = self else { return }`
...
you will get bazillion results.
The main problem is to understand when weakunowned should be used and even for experienced Swift users it is sometimes hard to grasp which one should be used as it strongly depends on the context. Thats why we have such situations were people add [weak self] regardless if is needed or not but it’s easier, and faster to add this than thinking about each case and for sure finding a memory leak which in case of closures is rarely pleasant experience.
I believe that whole community would love to see improvement in this area as writing guard let for self became like a mantra. We can improve this situation by compiler warnings and better tooling or/and improving the syntax of closures to lesser the problem.
I would be personally satisfied if at least for closures that returns Void we could solve it by the syntax sugar in a form that was already proposed few times. For any other closure I don’t think we need any additional syntax as probably it won’t be significantly shorter and more descriptive than typing guard inside the closure as we use to now.
{ [weak(guard) self] in ... }
{ [unowned(guard) self] in ... }
I would only suggest to even use shorter syntax to avoid writing weak and unowned and instead ? and !
Hi all, thanks for all the feedback so far. To bring further discussion back on track and to summarise:
There appears to be wide spread frustration with the current capture list syntax – particularly in regards to class types.
Common Cocoa APIs and idioms frequently and pervasively require developers to utilise non-owned callbacks to perform tasks without use of a retain cycle. It seems likely highly that the majority of capture lists 'in the wild' are of this variety.
The inline method of passing these callbacks often results in unclear and aesthetically dissatisfying code, with common and repetitive boilerplate that – apparent from these discussions – many developers have an aversion to.
The idiom of factoring out these inline methods to instance methods, and passing the instance method instead – whilst cleaning up the call-site – silently creates a strong reference that, from these discussions, clearly many developers aren't expecting.
The 'correct' syntax for factoring out these instance methods requires an intermediary forwarding closure of the same arity as the instance method that, I assume, must appear again and again in idiomatic Cocoa applications – and I imagine any code that makes use of class types and asynchronous routines.
Whilst there seems to be some argument on the solution, there is no doubt appetite for a solution.
In the interim – derived from the ideas of @sveinhal above – I've come up with something that I'll likely use in my own code to clean-up call sites where these callbacks occur.
It's not ideal as 1) it requires any class that uses it to conform to a protocol to gain access to the functionality (we can't extend AnyObject), and 2) it requires a method per arity as the obvious way using generics leads to a retain cycle.
Perhaps I'm interpreting your argument wrong, but unowned is very useful in certain contexts. Now granted those contexts are pretty narrow, and generally involve some tight coupling between types. This generally being, from my experience, when there's a strong Parent/Child relationship going on, and there's no concurrency involved.
Take this contrived example:
class Parent {
var name: String
private var child = Child()
private struct Child {
var action: () -> () = {}
}
init(name: String) {
self.name = name
self.child = Child(action: {[unowned self] in
print(self.name)
})
}
deinit {
print("Parent going away")
}
func doSomething() {
child.action()
}
}
var p: Parent? = Parent(name: "bob")
p?.doSomething()
p = nil
Now granted, this is fairly contrived. Most times I've used unowned isn't in capture lists, but as a modifier on a Child's reference to the parent.
It is fairly contrived, but I probably have more contrived code in production.
I agree that unowned in the case makes the ergonomics nicer, but [weak self] is still valid and safe. And it could be argued it's safer given theoretical (though ill-advised) future changes that would break the tidy ownership model.
There's this curious trend in the swift community to "always use weak to prevent a crash!", but actually, it's probably better for it to crash rather than fail silently and create difficult to diagnose bugs.
Anecdotally, most of my capture lists are [unowned self]. I agree that most of the time it's where there is some tight coupling between a parent and child, and so I know if the parent exists the child must also. Beyond providing a nice hard crash if my code is doing something unexpected it also saves me a guard.
For example, if you are submitting an animation to a property animator (which is a synchronous operation), and the view you're performing animatable property changes on is currently in scope, when you add that animation there is little point in using a weakly captured instance as you have the instance in the current scope and you know the animation closure will be executed immediately.
For asynchronous use cases it is often necessary to use weakly, but certainly not as a rule. Many of the reactive bindings I create use unowned because I guarantee the lifetime of the subscription is the same as the instance I'm performing operations on.
IMO unless there's a risk to data/system integrity, crashing is never an option. This seems like a prime use case for an assertion in the guard statement.
The ergonomics around this are currently horrible, but all syntax being equal I'm struggling to find a reason why selfshouldn't default to weak in an escaping closure.
In production code, safety and maintainability are the priority. [weak self] fulfills this in, (as far as I can tell), all cases with the only drawback of having to add a few lines of code where it may not be necessary. I don't like the way it looks and boilerplate always sucks...but that's a current shortcoming of the language and seems like more of an excuse than a reason.
TLDR: The reason why my code is safe should be due it being impossible not to be safe. Relying on my own intellect in saying "I'm sure it won't crash" is usually something I regret doing .