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.
Related
I have a class
class SomeClass {
lazy var property1: Int = {
return 1
}()
lazy var property2: Int = {
return self.property1
}()
deinit {
print("SomeClass will be destroyed")
}
}
If I have the following in playground:
var a: SomeClass? = SomeClass()
print(a?.property1)
print(a?.property2)
a = nil
then the variable a will be deinitialized as SomeClass will be destroyed message will appear.
However if I comment out the accesses to the properties like:
var a: SomeClass? = SomeClass()
//print(a?.property1)
//print(a?.property2)
a = nil
I still got the message SomeClass will be destroyed.
I would expect that there is a reference cycle as the closure of property2 is never called and it references self through self.property1.
Is there something special with lazy variables or just my assumption is wrong that property2 hold a reference to self?
The reason that there isn't is a reference cycle is because the closure isn't stored on a. If a stored the closure and the closure contained self then there would be a reference cycle.
For lazy properties, everything after the = isn't called until the first time you access property2. When you do, the closure is created, called, freed from memory, and then the value is returned to you. This is why you can get rid of the self. in the closure since it will never capture self.
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.
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.
I have encountered what would seem like an extremely simple issue to solve, and I think I may be missing something.
The program crashes when attempting to create a recursive variable (?) with the typed to a class while being a member of the said class. For example:
class A {
var x: A
init() {
x = A()
}
}
Checking the crash log suggests a recursion of sorts, with init() being called infinitely.
Is there a proper method/syntax to solve this sort of problem, given that I need the variable x to be typed to class A, and the initializer must initialize variable x to class A?
It's obvious that at some step you should left property x uninitialized. So, thats better to declare it as Optional, and initialize it after instance was created:
class A {
var x: A?
}
let mainObject = A()
let nestedObject = A()
mainObject.x = nestedObject
Not sure but i think you are looking for this
class A {
var x: A?
init() {
}
anothermethod() {
x = A()
}
}
and you can call this method like
let a = A()
a.anothermethod()
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?