Asynchronous function call conflicts with deinitialization of an unowned object - swift

I have code similar to this, related to event handling in an asynchronous context:
class A {
var foos: Set<Fooable>
}
protocol Fooable {
func bar()
}
class B {
var a: A
var foo: Foo!
init(a: A) {
self.a = a
}
func start() {
self.foo = Foo(self)
self.a.foos.insert(self.foo)
}
deinit {
<... *>
if self.foo != nil {
self.a.remove(self.foo)
}
}
class Foo: Fooable {
unowned let b: B
init(_ b: B) {
self.b = B
}
func bar() { <... #> }
}
}
I figured that this should be safe code: before an instance of b is gone, it cleans up all references to its foo, so the reference Foo.b should never be an issue.
However, I get this error from an access of self.b inside of Foo.bar() (run on some GCD queue, not main):
exc_breakpoint (code=exc_i386_bpt subcode=0x0)
The debugger shows that self.b is completely fine: not nil, all values are as they should be.
However, the debugger also shows that, at the same time, the main thread is busy deinitializing the corresponding B; it's paused in <... *>, i.e. before the reference to foo could be removed from a. So it makes sense to me that self.b would be a bad reference at this point in time.
This seems to be unfortunate timing -- but how can I do away with this crash potential? I can not prevent asynchronous calls to bar() from happening, after all!

Basically, we are breaking the precondition of unowned here: even though the debugger doesn't show it, Foo.b can become nil during the lifetime of a Foo. The compiler believed us when we claimed (by use of unowned) that it couldn't, so we crash.
There seem to be two ways out.
Make sure that Foo.b is the last object that holds a strong reference to the respective instance of Foo. Then, the two objects should be removed "together", resp. there is no way a call to Foo.bar() can happen while Foo.b is being deinitialized (or after that).
Make Foo.b a weak reference, i.e. declare it as weak var b: B?. That makes the code more messy, but at least it can be made safe.

Related

Why does closure capture reference while function does not? Also, why "lazy" keyword is required for closure declaration?

I experimented it with the following code in Xcode Playground:
class X {
var a = 3
init(a: Int) {
self.a = a
}
deinit {
print("\(self.a) is deallocated.")
}
func returnX() -> Int {
return self.a
}
lazy var anotherReturnX: () -> Int = {
return self.a
}
}
var e: X? = X(a: 6)
print(e!.returnX())
e = nil // prints "6 is deallocated."
var f: X? = X(a: 7)
print(f!.anotherReturnX())
f = nil // prints nothing
From the above code, I can see that no reference is captured in the function returnX(), thus e is deallocated once I set e to nil. However, a reference is captured in the closure anotherReturnX(), thus f is not deallocated. Apparently, this implies that a closure captures references while a function does not.
Additionally, when I first type out the code, I didn't include lazy keyword before the closure declaration, as I thought it would be unnecessary to do so. However it triggers a compile-time error. I infer that since the closure can only be accessed after instantiation, it must access to the instantiated self. But since what I am declaring here is effectively an "anonymous function", why would the closure access to self during instantiation anyway?
After putting in some thoughts, I found more contradictions. For instance, I understand that a reference is captured when a closure is called. However, during initialisation of X, I am simply assigning a closure to a variable without calling it, same as the declaration of other instance properties. Thus the closure should not do anything during initialisation, and compiling the code without keyword lazy should be fine. But compilation fails. I am not sure what goes wrong in my understanding.
I have read some related articles, such as strong/weak reference, retain cycle, lazy stored property. However, many explain "what happens" and do not say much about "why".
So other than the question raised in the title, I would also like to clarify, what makes function and closure different from each other such that the above situation happens?
Update:
The fact that closure captures reference while function does not is further "enforced" on me, since, according to the Xcode Compiler, I can rewrite return self.a as return a in returnX(), but I cannot do so in anotherReturnX. As such, I guess I would have to accept that, although function and closure are similar because each of them is "a bundle of functionalities", function is different from closure that it does not capture references. If I were to go deeper in the reason behind this, it would probably involve the design of Swift itself?
However, I still cannot understand why lazy keyword is required for closure declaration.
lazy var anotherReturnX: () -> Int = {
return self.a
}
The self here is a strong self.
When an object references another object strongly, ARC cant deallocate so a retain cycle is created. The reference should be weak to avoid a retain cycle by creating weak self inside the block.
lazy var anotherReturnX: () -> Int = { [weak self] in
return self?.a
}
returnX is a method of the class. Methods don't capture variables. self is an implicit local variable in methods, that is implicitly passed to the method when the method is called.
anotherReturnX is a property that is assigned a closure lazily. That closure captures outside variables that are used within it, including self. That capturing creates a strong reference from the closure to the X instance, which, combined with the strong reference from the X instance to the closure, creates a retain cycle.

Is it safe to pass variable created into function to closure?

Everyone knows standard situation with retain cycle.
class TestClass {
var aBlock: (() -> ())? = nil
let aConstant = 5
init() {
print("init")
aBlock = {
print(self.aConstant)
}
}
deinit {
print("deinit")
}
}
var testClass: TestClass? = TestClass()
testClass = nil
but what about situation like this:
class A {
let b: B
let c: C
init() {
b = B()
c = C()
}
func foo() {
let localC = c
b.bar {
localC.execute()
}
}
}
B, C are classes.
I copied c and passed into b.bar closure as localC. In my opinion this situation does not create retain cycle and there will be no problems with deallocation of A.
But I am not 100% sure and I want to ask some with more experience about this. Someone could explain me what happens with references? Tnx.
The way you set it up should not create any retain cycles.
localC is unnecessary. All that does is create another reference to the underlying instance of c. They are identical. Modifying localC would also modify c. They point to the same object. You would have to explicitly copy() in order for them to point to different objects.
With that in mind, this is a diagram of the references:
As you can see, there is no retain cycle being created.

swift when static variable was released

I want to know when static variable will be released, so i create like below:
class A {
init() {
print("A init")
}
deinit {
print("A deinit")
}
}
class B {
static let a = A()
deinit {
print("B deinit")
}
init() {
print("B init")
}
}
var b: B? = B()
B.a
b = nil
When variable a's deinit was called? If b = nil then A's deinit wasn't called.
Objects will only be deinitialized when nothing else is holding a strong reference to it.
In your case, b is not holding a reference to a. The class B is.
Setting b to nil does not do anything to a because b never ever held a reference to a. b is essentially irrelevant. a and b are non-related objects.
Now that we know the class B is holding a reference to a, can we somehow destroy the class B so that a can be deinitialised? The answer is no. a is like a variable in the global scope. a will only be deinitialised when the program stops.
Another way to make something get deinitialised is by setting all the references to it to refer to something else. But since in this case a is declared with let, you can't really change it.
First, of all When you define static properties and method into a class (or struct), those variables are kept in the Permanent Generation area. and it will be shared among all the instances (or values).
This will be released by two ways:
1: When the classes are released but it is impossible to see Because
Classes are going in a special area on the heap: Permanent Generation
and when the application will terminate classes will be released
2: You can assign nil forcibly like this
class A {
init() {
print("A init")
}
deinit {
print("A deinit")
}
}
class B {
static var a:A? = A()
deinit {
print("B deinit")
}
init() {
print("B init")
}
static func call(){
a = nil
}
}
var b: B? = B()
B.a
B.call() //forcely call
b = nil
Output
B init
A init
B deinit
A deinit
You are saying that b is nil. This does not change B.a because a is a static member. In your example, a is not deinitialised. If you want the deinit to be called, you have to assign a new object to B.a. However, B.a is a constant (let). You can change it to var, otherwise this particular object will never be deinitialized.
class B {
static var a = A()
\\ ...
}
B.a = A() //deinit of the old `B.a` is called
In this case, it won't since B has a strong reference of A, but you could make something like: static weak var a = A() on your B class. And when B = nil, it will call the deinit of A and then deinit of B.

Lazy initialisation and retain cycle

While using lazy initialisers, is there a chance of having retain cycles?
In a blog post and many other places [unowned self] is seen
class Person {
var name: String
lazy var personalizedGreeting: String = {
[unowned self] in
return "Hello, \(self.name)!"
}()
init(name: String) {
self.name = name
}
}
I tried this
class Person {
var name: String
lazy var personalizedGreeting: String = {
//[unowned self] in
return "Hello, \(self.name)!"
}()
init(name: String) {
print("person init")
self.name = name
}
deinit {
print("person deinit")
}
}
Used it like this
//...
let person = Person(name: "name")
print(person.personalizedGreeting)
//..
And found that "person deinit" was logged.
So it seems there are no retain cycles.
As per my knowledge when a block captures self and when this block is strongly retained by self, there is a retain cycle. This case seems similar to a retain cycle but actually it is not.
I tried this [...]
lazy var personalizedGreeting: String = { return self.name }()
it seems there are no retain cycles
Correct.
The reason is that the immediately applied closure {}() is considered #noescape. It does not retain the captured self.
For reference: Joe Groff's tweet.
In this case, you need no capture list as no reference self is pertained after instantiation of personalizedGreeting.
As MartinR writes in his comment, you can easily test out your hypothesis by logging whether a Person object is deinitilized or not when you remove the capture list.
E.g.
class Person {
var name: String
lazy var personalizedGreeting: String = {
_ in
return "Hello, \(self.name)!"
}()
init(name: String) {
self.name = name
}
deinit { print("deinitialized!") }
}
func foo() {
let p = Person(name: "Foo")
print(p.personalizedGreeting) // Hello Foo!
}
foo() // deinitialized!
It is apparent that there is no risk of a strong reference cycle in this case, and hence, no need for the capture list of unowned self in the lazy closure. The reason for this is that the lazy closure only only executes once, and only use the return value of the closure to (lazily) instantiate personalizedGreeting, whereas the reference to self does not, in this case, outlive the execution of the closure.
If we were to store a similar closure in a class property of Person, however, we would create a strong reference cycle, as a property of self would keep a strong reference back to self. E.g.:
class Person {
var name: String
var personalizedGreeting: (() -> String)?
init(name: String) {
self.name = name
personalizedGreeting = {
() -> String in return "Hello, \(self.name)!"
}
}
deinit { print("deinitialized!") }
}
func foo() {
let p = Person(name: "Foo")
}
foo() // ... nothing : strong reference cycle
Hypothesis: lazy instantiating closures automatically captures self as weak (or unowned), by default
As we consider the following example, we realize that this hypothesis is wrong.
/* Test 1: execute lazy instantiation closure */
class Bar {
var foo: Foo? = nil
}
class Foo {
let bar = Bar()
lazy var dummy: String = {
_ in
print("executed")
self.bar.foo = self
/* if self is captured as strong, the deinit
will never be reached, given that this
closure is executed */
return "dummy"
}()
deinit { print("deinitialized!") }
}
func foo() {
let f = Foo()
// Test 1: execute closure
print(f.dummy) // executed, dummy
}
foo() // ... nothing: strong reference cycle
I.e., f in foo() is not deinitialized, and given this strong reference cycle we can draw the conclusion that self is captured strongly in the instantiating closure of the lazy variable dummy.
We can also see that we never create the strong reference cycle in case we never instantiate dummy, which would support that the at-most-once lazy instantiating closure can be seen as a runtime-scope (much like a never reached if) that is either a) never reached (non-initialized) or b) reached, fully executed and "thrown away" (end of scope).
/* Test 2: don't execute lazy instantiation closure */
class Bar {
var foo: Foo? = nil
}
class Foo {
let bar = Bar()
lazy var dummy: String = {
_ in
print("executed")
self.bar.foo = self
return "dummy"
}()
deinit { print("deinitialized!") }
}
func foo() {
let p = Foo()
// Test 2: don't execute closure
// print(p.dummy)
}
foo() // deinitialized!
For additional reading on strong reference cycles, see e.g.
"Weak, strong, snowned, oh my!" - A guide to references in Swift
In my onion, things may work like this. The block surely capture the self reference. But remember, if a retain cycle is done, the precondition is that the self must retain the block. But as you could see, the lazy property only retains the return value of the block. So, if the lazy property is not initialized, then the outside context retains the lazy block, make it consist and no retain cycle is done. But there is one thing that I still don't clear, when the lazy block gets released. If the lazy property is initialized, it is obvious that the lazy block get executed and released soon after that, also no retain cycle is done. The main problem lies on who retains the lazy block, I think. It's probably not the self, if no retain cycle is done when you capture self inside the block. As to #noescape, I don't think so. #noescape doesn't mean no capture, but instead, means temporary existence, and no objects should have persistent reference on this block, or in an other word, retain this block. The block could not be used asynchronously see this topic. If #noescape is the fact, how could the lazy block persist until the lazy property get initialized?

Closure closing strongly over a class type instance that go out of scope; can the instance be accessed somehow via the closure instance?

Question: For the case of ()-return closures, is there any way to access a variable that ARC lets live only due to a single strong reference from a closure closing over it? In the example below: accessing bb in the closure.
Below follows an example to show what I mean.
In the Language Reference - Expressions, it reads
Capture Lists
By default, a closure expression captures constants and variables from
its surrounding scope with strong references to those values. You can
use a capture list to explicitly control how values are captured in a
closure.
...
Consider the following example, using a weak and a strong capture of two class type instances
class MyClass {
var myInt : Int = 0
func printMyInt() {
print(myInt)
}
}
func getClosure(a: MyClass, _ b: MyClass) -> (() -> ()) {
return { [weak aa = a, bb = b] in
aa?.printMyInt() ?? print("Lost reference")
bb.printMyInt()
}
}
func foo() -> (() -> ()) {
let a = MyClass()
let b = MyClass()
let closure = getClosure(a, b)
closure() // 0, 0
a.myInt = 1
b.myInt = 2
closure() // 1, 2
return closure
}
If foo() is called, then at the return of closure, MyClass instances a and b are out of scope. In the closure itself, aa keeps a weak reference to a, so a (memory) will be "destroyed" by ARC, and aa will become nil.
However, since the closure closes over b with a strong reference, ARC will retain the memory for b until the closure itself goes out of scope.
let closure = foo()
closure() // Lost reference, 2 <-- OK, expected
/* 'b' (not the reference, but the object in memory) still lives, but
cant be explicitly accessed? */
Hence my question: how to access, in this case, bb within the closure.
What I've tried
I've tried without success using Mirror:
var bar = Mirror(reflecting: closure)
print(bar.children.count) // 0
Also, I know we can "access" bb in the example above by adding a return type (MyClass) to the closure, but I'm wondering if we can actually access it without such a workaround (hence the ()-return specific closure in the question above).
Where I've looked prior to posting this question
I've been searching around SO for a possible existing threads that asks and answers this question, but the closest one I found,
Getting data out of a closure in swift,
don't really answer my question here. (Or perhaps the workarounds in the answers to that question does, and the answer to my question above is "you can't"?)