Object created within a function disappears despite being passed further - swift

Coming from a different language I got surprised by a silent bug where an object which is passed to a method as a callback suddenly is never called. The reference to a callback is somehow lost.
Minimal (not runnable) example of a problem:
class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
func bar() {
let out = AVCaptureMovieFileOutput()
let delegate = Foo() //nonsensical in this case, in normal case diff. object will be used
out.startRecording(to: /*...*/, recordingDelegate: delegate)
//Result: delegate methods are never called
}
}
Minimal (not runnable) example of a "solution":
class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
func bar() {
let out = AVCaptureMovieFileOutput()
out.startRecording(to: /*...*/, recordingDelegate: self)
//Result: delegate methods are called when approperiate
}
}
I'm puzzled...
Why does that happen?
How to prevent such situation?
Is such silent failure by design?
This question stems from the AVCaptureMovieFileOutput never calls delegate on screen recording

Most delgates are weak so that they do not create a retain cycle, see Automatic Reference Counting (ARC). Most of this is assuming that the delegate storage for what you are using is weak.
In your first example the only strong reference to the object is held by the function bar, as the delegate is a weak reference. Once the function ends, the only remaining strong reference is gone and the object is free to be deleted.
class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
func bar() {
let out = AVCaptureMovieFileOutput()
let delegate = Foo() //object created, and strong reference stored in variable called delegate
out.startRecording(to: /*...*/, recordingDelegate: delegate) // object passed in and likely stored in a weak variable inside of the `out` object. This means it will not keep a strong reference to your Foo object.
//Result: delegate methods are never called
}// local variable called delegate goes out of scope, strong reference to your Foo object goes away, there are no more strong references, can be deleted.
}
In the second example when using self as the delegate, self is likely sticking around after the end of the bar function, so the delegate remains.
class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
func bar() {
let out = AVCaptureMovieFileOutput()
out.startRecording(to: /*...*/, recordingDelegate: self) // pass `self`, which presumably has something else referencing it with a strong reference, so it stays alive
//Result: delegate methods are called when approperiate
} // `self` still has strong references to it (somewhere else) keeping it alive after the function call, so the weak reference that is being used to call the delegate methods can still operate! Yay!
}
Hopefully that answers the "why."
As for prevention, you need to make sure you keep a strong reference to any delegates (or weak variables) that you want to stay alive.
This behavior is by design as it is used to prevent retain cycles and memory leaks. When designing your own classes with delegates it is up to you to use weak appropriately to prevent retain cycles when necessary.
As for the silence of the failure, there are many cases where the delegates are optional, and it is not considered a failure for the delegate to be nil and for the delegate functions to not get called. Many times the functions are called like delegate?.delegateMethod() intentionally so that the function will be called if you want to have a delegate and it won't cause a problem if you don't want to have a delegate.

Related

Swift closures causing strong retain cycle with self

I just want to know if I am understanding this correctly or not. So according to the apple docs when you create a closure as a property of a class instance and that closure references self(The class that created the closure property) this would cause a strong retain cycle an ultimately the class nor the closure will ever get released. So in laymen terms that means that if I have a class that has a property and that property is a closure, and once I assign the functionality of that closure within the class that declares the closure property that will cause a strong retain cycle. Heres a quick example of what I mean
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = {
self.dismiss(blahBlahBlah)
}
}
}
This ultimately causes a retain cycle since the closure keeps a strong reference to self, which is the class that creates the closure property. Now to fix this according to apple I would define a capture list like so
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = { [weak self] in
self?.dismiss(blahBlahBlah)
}
}
}
Notice how I put the [weak self] before the in statement. This lets the closure know to only hold a weak reference to self and not a strong reference. IM supposed to use weak when self can out live the closure or unowned when the closure and self live for the same duration.
I got this information from here Automatic Reference Counting and in the Strong Reference Cycles for Closures section of that link, theres this sentence "A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance" Im about 90% sure Im understanding this correctly but theres just that 10% of doubt. So do I have this correct?
The reason why im asking this is because I use callbacks for some of my buttons in my views. And those callbacks call to self but the self in that scenario is the view controller that is responding to the callback not the actual view itself. This is where im doubting myself because I from that sentence I highlighted I don't think I need to put [weak self] on all those button callbacks, but im just making sure. Heres an example of this
class SomeViewController {
let someSubview:UIView
override viewDidLoad() {
//Some Subview has a button and in that view I just have some action that gets fired off calling the callback here in the view controller I don't need to use the [weak self] in this scenario because closure property is not in this class correct?
someSubview.someButtonsCallback = {
....run code then
self?.dismiss(blahBlahBlah)
}
}
Yes, that can still cause a retain cycle.
The simplest retain cycle is 2 objects that each have strong references to each other, but 3-way and larger retain cycles are also possible.
In your case, you have view controller who's view contains a button (a strong reference.) The button has a strong reference to a closure. The closure strongly references the view controller using self. So the view owns the button. The button owns the closure. The closure owns the view controller. If you dismiss the view controller (say it was a modal) then it SHOULD be deallocated. However, since you have this 3-way retain cycle, it won't be deallocated. You should add a deinit method to your view controller with a print statement and try it.
The solution is to add a capture list (The [weak self] bit) just like you did in your first example.
Note that a common pattern is to add a capture list, and then map the weak variable to a strong variable inside the closure:
let myClosure = { [weak self] in
guard let strongSelf = self else { return }
//...
strongSelf.doSomething()
}
That way, if the closure is still active but the object that owns it was released, the guard statement at the beginning detects that self is nil and exits at the beginning of the closure. Otherwise you have to unwrap the optional every time you refer to it.
In certain cases it's also possible that the object in the capture list (self in these examples) could be deallocated in the middle of the closure being executed, which can cause unpredictable behavior. (Gory details: This is only when the closure is run on a different thread than the owner of the object in the capture list, but completion handlers are pretty commonly run on a background thread, so it does happen)
Imagine this:
let myClosure = { [weak self] in
self?.step1() //1
//time-consuming code
self?.property = newValue //2
//more time-consuming code
self?.doSomething() //3
//even more time-consuming code
self?.doSomethingElse() //4
}
With the code above, if the closure is run on a background thread, its possible that self would still be valid at step 1, but by the time you execute step 2, self has been deallocated. The same goes for steps 3 and 4. By adding the guard strongSelf = self else { return } at the beginning of the closure you test at the entry of the closure to make sure self is still valid, and if it is, you make the closure create a strong reference that only lives as long as the closure takes to run, and that prevents self from being deallocated while the closure code is executing.)

Will this cause a retain cycle Swift?

I have this code and I'm questioning if I need to use a capture list to make my reference to self weak.
Right now I'm thinking that getTextFileData and .main.async are static methods, therefore, this will not cause a retain cycle. However, I do access the games property, kinda not sure.
NPWebService.getTextFileData { (games, success) in
if success {
self.games = games
DispatchQueue.main.async {
self.updateUI()
}
}
}
This wouldn’t cause a retain cycle because it looks like a static method on a different type. So the getTextFileData method will temporarily retain the closure you are passing in until any asynchronous work is complete, and the closure will temporarily retain self. But when the work is complete and the closure is done executing, those temporary retains will expire and automatic memory management can clean up as appropriate.
The danger of a retain cycle is when you have a closure the that references / captures self, and self also retains the closure, for example. Like this:
class GameController {
var games: [Game]?
// self retains the closure as a property
let updateClosure:([Game], Bool)->() = {
games, success in
if success {
self.games = games // and the closure captures self. Each retains each other indefinitely, this is a retain cycle and neither this closure nor self will ever be deallocated
}
}
func load() {
NPWebService.getTextFileData(updateClosure)
}
}
So normally weak self or unowned self in closure capture lists are only needed:
if self or something retained by self will be retaining that closure (this is rarely the case when a closure is created locally and transiently at the call site to pass into a method as an argument)
if for non-retain cycle reasons, the desired behavior is to allow self to be deallocated before some asynchronous work is completed, and before the closure is invoked. In this case the closure shouldn’t strongly capture self and instead should weakly capture it and check if it still exists before making use of self when the closure is invoked

Confusions about weak delegate in swift

Let us suppose we have a protocol
protocol MyProtocol {
fun someFunc()
}
class AClass {
var delegate: MyProtocol?
}
AClass doesn't care if the delegate is a class or struct. What I want is sometimes the delegate can be a class and sometimes it can be assigned to a struct.
My question is if I should make the delegate to be "weak".
If so, I have to make MyProtocol be a "class Protocol" so that the delegate has to be a class only.
If not, when I assign the delegate to class, how can I avoid retain cycle?
Thanks for any hint!
should make the delegate to be "weak"
The answer is that if MyProtocol is not restricted to classes, you cannot make it weak, the compiler won't let you.
The reason for the above is that structs are value types. There isn't a reference that can be strong or weak, because logically the entire struct is copied in when you assign the delegate.
how can I avoid retain cycle?
This means that you have got to be careful that your delegate contains no strong references back to the instance of the class. So, for instance
struct ConcreteDelegate: MyProtocol
{
fun someFunc() {}
var instance: AClass
init()
{
instance = AClass()
instance.delegate = self
}
}
Causes a reference cycle. It can be broken by declaring instance as
weak var instance: AClass!
Alternatively, and a better solution (IMO), your protocol functions can pass the instance as a parameter so the delegate never needs to store a reference to the instance.
protocol MyProtocol {
func someFunc(caller: AClass)
}
You'll see the above approach adopted in Cocoa in lots of places, for example with the table view data source protocol.
I think that you forgot that struct are not reference type but a value type. Meaning that a class has a reference in the memory heap but structures, enums haven't. By remembering this fact, there is no meaning to put weak if the delegate of your protocol is a struct because it can't cause a retain cycle.
You need to worry about retain cycles when you use only classes. If your delegate of your protocol is a class put weak if you think that your class have a reference of your protocol AND your protocol can have a reference of your class put weak that's the retain cycle.
If you want to check it put deinit functions when you are testing and see if your class is correctly deinit and not kept in memory.
It's basically what I know hope it will help you.

Is method closure retaining the instance in swift?

In swift, I can use instance methods as closures, for example, assigning the method to a callback
self.someView.someCallback = self.doSomething
So, is self strongly referenced here in self.doSomething? Does the line above create a reference loop?
There are two possible scenarios based upon your code snippet:
If doSomething is a instance method of self, then, yes, that line establishes a strong reference. Remember that Closures are Reference Types. You can easily confirm this and is easily confirmed empirically. Consider:
class ViewController: UIViewController {
var foo: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
foo = bar
foo?()
}
func bar() { ... }
}
If I present and dismiss this view controller three times, and then use Xcode’s “Debug Memory Graph”, , I will see those three instances still lingering in memory (on the left) and if I select one, it will show me the strong reference cycle visually in the center panel:
And because I used the “Malloc stack” feature, on the right panel I can see precisely where the lingering strong reference is, namely in viewDidLoad where I set that closure.
However, if doSomething is not a function, but rather is a closure, then that line, itself, does not establish a strong reference, but rather it becomes a question of whether the closure, itself, refers to self and, if it does, whether there is a [weak self] or [unowned self] capture list or not. For more information, see Strong Reference Cycles for Closures.
In order to have a retain cycle, you need to have a strong reference on each direction, i.e.:
Object A strongly references Object B
Object B strongly references Object A
Assuming self in the code you shared is a View Controller, and assuming someView is a strong reference to a view, we could say that:
Object A (View Controller) strongly references Object B (Some View)
Now if Object B (Some View) has a strong reference back to the View Controller, you will have a retain cycle.
Assuming doSomething is a method in your ViewController, and not a closure, you will have a retain cycle
An easy way to check this, is by implementing deinit in both your Some View and your View Controller, like so:
class SecondViewController: UIViewController {
var someView: CustomView?
override func viewDidLoad() {
super.viewDidLoad()
someView = CustomView(frame: view.frame)
someView?.someCallback = doSomething
}
func doSomething() {
}
deinit {
print(#function)
}
}
final class CustomView: UIView {
var someCallback: (() -> Void)?
deinit {
print(#function)
}
}
You will see that the prints on deinit are never printed out in the console. However changing the way you assign someCallback to:
someView?.someCallback = { [weak self] in
self?.doSomething()
}
will cause deinit to run, thus breaking the retain cycle
Edit:
Or even, as an alternative:
weak var weakSelf = self
someView?.someCallback = weakSelf?.doSomething
(Even though this is using a weak reference, because this expression is evaluated at the time the assignment of someCallback is performed, not at the time it is executed, this will still become a strong reference) - Thanks #Rob
In Swift, declare a closure type variable, and would like to assign a func to it, prevent from the retain issue,
just do as follow, search the answer for all day long, eager to share:
self.someView.someCallback = {
[unowned self] in self.doSomething()
}

Swift - Expecting a leak after strongly capturing self in closure

Can anyone please explain why this doesn't leak?
I'm capturing self within a closure so I would have two strong pointers pointing at each other, therefore, the deinit message shouldn't ever be called for the Person object.
First, this is my class Person:
class Person {
var name: String
init(name: String) { self.name = name }
deinit { print("\(name) is being deinitialized") }
}
And this is my ViewController's implementation:
class ViewController: UIViewController {
var john:Person?
func callClosureFunction( closure:(name:Bool) -> () ) {
closure(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
self.callClosureFunction { (name) in
self.john?.name = "John Appleseed"
self.john = nil
// xcode prints - John Appleseed is being deinitialized
}
}
}
I was expecting to be able to fix the issue by doing:
self.callClosureFunction { [weak self] (name) in ...
But that wasn't even necessary. Why?
Since your view controller is not retaining the closure, there is no circular reference. If you wrote this:
class ViewController: UIViewController {
var john:Person?
var closure:(Bool)->()?
func callClosureFunction( closure:((name:Bool) -> ())? ) {
closure?(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
closure = { (name) in
self.john?.name = "John Appleseed"
// Because this closure will never be released, the instance of Person will never deinit either
}
self.callClosureFunction(closure)
}
}
then the view controller would retain the closure and the closure would retain the view controller via its reference to self. Therefore, neither would be released, and if you don't explicitly set self.john = nil (which you did in your original example), then the Person instance would never get deninit called.
It's quite common to inappropriately use weak self in closures when not necessary (and this can actually lead to some obscure bugs). The key rule to remember is that weak references are not the default in general under ARC. Strong should be the default unless it would lead to a retain cycle, in which case weak should be used only to break that circular reference. Same for closures: strong self should be the default, unless the self in this case also has a strong reference to the closure itself.
You're capturing self which points to ViewController, but you're wondering about the Person instance.
Person is actually not circular referenced and therefore gets de-initalized and released just fine when you set it to nil at the end of your closure.
Implement deinit for ViewController and see how that works.
I'm capturing self within a closure so I would have two strong pointers pointing at each other, therefore, the deinit message shouldn't ever be called for the Person object.
No, you have one strong pointer, from the closure to self. There's no cyclic reference back from the closure to self. Thus, you have a directed acylic graph, which is no problem for ARC.
However, your experiment is flawed, from the get-go. Even if the closure was captured, the John Appleseed Person object would still deinit. This object's lifecycle is exclusively dependent on on the john reference from your ViewController. When you set that reference to nil, you're removing the last reference to the John Appleseed object, thus it's deinitialized.