Swift weak reference is nil when that object's deinit is executing - swift

I found a interesting thing:
class A {
let name = "A"
deinit {
print(self.name)
print(self === Weak.value)
print(Weak.value?.name ?? "nil")
}
}
enum Weak {
static weak var value: A? = nil
}
var a = A()
Weak.value = a
a = A() //to call deinit
Output is
A
false
nil
So, when an object is executing its deinit method, it can access its own properties. But another weak reference to this object has become of nil even this object has not been deallocated actually at this time.
According to This article, there is a side-table of each object. Here is my assumption: When an object's deinit method is executing, this object hasn't been deallocated. But the pointer from this object's side-table, to this object, has already been removed (or marked as nil). So no one can access it except itself. This is actually how Swift 4 works.
Is what I said right? This post is not a question, just want more details. It's so kind if someone can explain more.

Related

Object created within a function disappears despite being passed further

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.

Xcode 10 - Instance will be immediately deallocated because property is 'weak'

I recently downloaded Xcode 10 and I noticed an apparent bug when using weak or unowned variables. I managed to create a simple example that showcases the problem so that people can recreate it.
class MainClass {
weak var weakClass: SomeClass!
init() {
// WARNING: Instance will be immediately deallocated because property 'weakClass' is 'weak'
self.weakClass = SomeClass()
}
}
class SomeClass {}
As the error says, weakClass immediately deallocates once MainClass is initialized and is always nil.
I have opened up the same playground with Xcode 9.3 and I can confirm that the code works fine with no errors or warnings
Is this a bug in Xcode 10 or am I not getting something. If it is, is there any workarounds?
EDIT: Original Example
class LoginCoordinator {
var viewModel: LoginViewModel?
var viewController: LoginViewController?
init() {
viewModel = LoginViewModel()
viewModel?.coordinator = self
viewController = LoginViewController(viewModel: viewModel!)
}
}
class LoginViewModel: ViewModelDelegate {
weak var coordinator: LoginCoordinator?
}
coordinator is always nil in LoginViewModel
AppDelegate.swift
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func setupView() {
let coordinator = LoginCoordinator()
let navigationController = UINavigationController(rootViewController: coordinator.create)
navigationController.isNavigationBarHidden = true
navigationController.navigationBar.isTranslucent = false
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
window?.layer.cornerRadius = 6
window?.layer.masksToBounds = true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
setupView()
return true
}
To understand this you must know the concept of ARC. ARC concept is automatic reference count means ARC will keep something in memory, as long as an allocated memory is strongly referenced by some variable. If it(ARC) found some allocated memory doesn't have any strong reference it will dealloc it. So the warning weakClass immediately deallocates once MainClass is initialized and is always nil. Because it doesn't have any strong reference.Please comment any doubt.
One example below for retain cycle creation:
class A {
var classBObject: B?
init() {
classBObject = B()
classBObject.classAObject = self // Creates a retain cycle
}
}
class B {
var classAObject: A? // Strong(by default all are strong) variable create retain cycle
}
So, in class B if we take weak var classAObject retain cycle will not happen.
This is the purpose of weak. Swift uses reference count to manage memory. A strong pointer increases the reference count of the pointed object by 1, a weak pointer does not increase reference count. An object with 0 reference count will be deallocated.
Your instance of SomeClass only pointed by a weak pointer, so its reference count is 0. As a result it is deallocated immediately.
Weak is useful to avoid retain cycles. For example, in escaping closure and in delegation design pattern.
The question is, "is that reference strongly referenced elsewhere? If so, it will not be deallocated."
I propose that Apple's warning message is misleading. I think that it should state that it will be deallocated immediately when its containing object is deallocated or when other strong references to it are deallocated.
Here's why.
We have this warning on an instance in a view controller and the weak var is not deallocated immediately. The view controller appears, the weak var is instantiated, we wait, click a button that hits a breakpoint and yup, the weak var is still not nil. Yet when the view controller disappears and is deallocated, the weak var is deallocated immediately.
But why? Well, by the time we come to the part of code that has a weak reference to the variable, other code already has caused this variable to have retain count of 3. This means that even though it's weak, it can't be immediately dismissed.
You can check this with po myObject.retainCount. It's not guaranteed to be accurate, but it will give you an idea. If the object's retainCount > 1 and it's strongly linked somewhere else, (please put a comment in your code to indicate where it is strongly referenced), weak will work. To avoid a compiler warning, don't reference the object directly, but the strong reference in the other object.
So, I think that Apple needs to reword this warning because it's surely misleading.
Further, given that a Swift property doesn’t have a corresponding instance variable, it makes sense that when you give a value to a weak property, it is immediately deallocated. I run into a similar problem here where my SceneDelegate asks for the rootViewController of this AppCoordinator :
class AppCoordinator {
private weak var navigationController : UINavigationController!
var rootViewController : UIViewController {
navigationController = UINavigationController()
return navigationController // <-- here the app crashes: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
}
}

Captured weak reference pointed to wrong object

If I weakly reference self in a closure:
{[weak self] in self!.doSomethinmg()}
And self is deallocated, yet the closure continues to exist. Is it possible that self in the closure can become non-nil at some point in the future -- pointing to some random new object as determined by the runtime environment?
A pointer is a variable whose value is a memory address. The same is
true for a weak pointer, but the value of a weak pointer is
(due to some runtime magic) set to nil if the pointed-to object is
deallocated. It is irrelevant if any new object is created at the
same memory location later, the weak pointer variable stays nil.
So
{ [weak self] in /* ... */ }
creates a closure with a weak pointer variable. That variable
is set to nil when the pointed-to object is deallocated.
That may happen before the closure is called or during the execution
of the closure, so even
{ [weak self] in
if (self != nil) self!.doSomethinmg()
}
is unsafe and can crash if the object is deallocated between the test
and the method call.
But at any point, the weak pointer either points to
the original object instance or is nil. It will
never point to some other object instance. (That may happen with
unowned references.)
As Lorenzo says, don't
force unwrap the weak pointer. Either use optional chaining or
create a strong reference inside the closure.
It depends on what you want to achieve.
Martin is suggesting the right thing. In order to guarantee you don't have any crash and continue to deal with that instance you can use weak/strong dance. Otherwise, use self?.
So for example, with the weak/strong dance you can do the following:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
Otherwise
{ [weak self] in
self?.doSomething()
}
While in the first case the instance that belongs to self will continue to exist until the closure will be discarded, in the second case, instead, since the instance will be put to nil, it will behave as a sort of non-op.
If all the strong references to an instance are removed, then the instance will eventually be deallocated. But that doesn't necessarily mean the references that were referring to it will be reused. All the strong references are obviously gone because they had to be in order for it to be deallocated in the first place. So whatever that means for the memory that those references required for their referring duties is irrelevant to the application, because the references don't exist anywhere in it anymore.
Which leaves unowned and weak references left. Apple makes it pretty clear that attempting to access the value of an unowned reference after the instance has been deallocated is a no, no:
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
So that is also irrelevant to the application, simply because it's a hard-rule not to be broken.
Which leaves, last but not least, weak references. Apple says this about weak references:
Because a weak reference does not keep a strong hold on the instance
it refers to, it’s possible for that instance to be deallocated while
the weak reference is still referring to it. Therefore, ARC
automatically sets a weak reference to nil when the instance that it
refers to is deallocated.
...
You can check for the existence of a value in the weak reference, just
like any other optional value, and you will never end up with a
reference to an invalid instance that no longer exists.
The key take away here is that the reference is set to nil. And even though nil represents nothing, it's still a valid value. And I feel it may be safe to assume that the runtime environment won't steal a reference and use it for another purpose when it's still pointing to a valid value. Imagine what it'd be like otherwise.
So the relevance to the application here for weak references is just that they may become nil at some point; and as #MartinR showed in his answer, this may even happen mid-execution of the closure. So the final solution would seem to be creating a strong reference from the weak reference before using it, aka the "weak/strong dance":
Either:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
or
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
If the closure consists of a single optional chain:
{ [weak self] in
self?.doSomething()
}
will simply result in a non-op if self is nil, but no idea if this bears any guarantee that self won't be deallocated mid-execution of the closure if it's arbitrarily longer:
{ [weak self] in
self?.doSomething()
...
self?.doSomethingDownTheLine()
}
So in this case, doing the weak/strong dance will guarantee that your closure will be all-or-nothing:
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
...
strongSelf.doSomethingDownTheLine()
}

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.

Strong Reference Cycles for Closures?

Swift Closure will have a strong reference cycle when it refers to self like this example:
class Test {
var name = "Hello"
func doSomething() {
{() -> Void in
self.name = "otherName"
}()
}
}
In the previous example, I created a strong reference cycle so I have to fix it with:
class Test {
var name = "Hello"
func doSomething() {
{[unowned self] () -> Void in
self.name = "otherName"
}()
}
}
Question: If I refer self in a closure do I have to use alway unowned self or are there cases where I have to use weak self?
If I refer self in a closure do I have to use alway unowned self or are there cases where I have to use weak self?
Neither. In most cases, just refer to self normally and do nothing with its memory management. You only have to worry about memory management if there is a danger of a retain cycle, and unless you store the closure somewhere, such as a property of self, there is no such danger.
You can easily prove this by adding a deinit implementation:
class Test {
var name = "Hello"
func doSomething() {
{() -> Void in
self.name = "otherName"
}()
}
deinit {
println("bye")
}
}
Now make a Test instance and immediately release it:
func testTest () {
let t = Test()
}
You see "bye" in the console, proving that the instance was released in good order. There was never any kind of "strong reference cycle" in this code. Your concerns are groundless.
[By the way, you are using the word "closure" wrong. Every Swift function is a closure. If there were a retain cycle issue merely because of using the word self in a closure, every Swift function would be subject to this issue - and clearly that is not the case. The place where weak and unowned self comes into play is in an anonymous function - and only, as I said before, if that anonymous function is itself also retained by self.]