Swift - deinit not called - memory

Hmm...
I'm having a little problem with an unexpected behaviour in Swif4 memory management. In fact I'm missing a deinit call
Basically the layout of the code part failing is like this:
class A {
init() {
print("A init \(unsafeBitCast(self, to: UnsafeMutableRawPointer.self)) called")
}
deinit {
print("A deinit \(unsafeBitCast(self, to: UnsafeMutableRawPointer.self)) called")
}
func c() {
print("A c called")
}
}
class B {
var a : A
init() {
a = A() <-- required because a is not optional
}
func c() {
a = A()
a.c()
}
}
var b = B()
b.c()
b.c()
b.c()
I simulated this in playground and the (expected) printout was this (w/o comments):
A init 0x000060c00000c540 called <-- initial init
A init 0x000060c00000c800 called <-- first b.c()
A deinit 0x000060c00000c540 called
A c called
A init 0x000060400000c4c0 called <-- second b.c()
A deinit 0x000060c00000c800 called
A c called
A init 0x000060400000c4a0 called <-- third b.c()
A deinit 0x000060400000c4c0 called
A c called
Unfortunately my real life classes don't behave like so. In fact they act like so:
A init 0x000060c00000c540 called <-- initial init
A init 0x000060c00000c800 called <-- first b.c()
A deinit 0x000060c00000c540 called
A c called
A init 0x000060400000c4c0 called <-- second b.c()
A deinit 0x000060c00000c800 called <-- missing!
A c called
A init 0x000060400000c4a0 called <-- third b.c()
A deinit 0x000060400000c4c0 called <-- missing!
A c called
So, basically only the first deinit appears, no subsequents. I fear memory leaks (although Instruments doesn't give me a hint).
Any idea, what operations could provoke this behaviour? I don't have circular references, at least I don't see them.

OK, fixed. The problem was, that my "A" class was held as reference by a URLSession (as delegate). Because this session was not terminated properly, the A object was not deinitialized.

Related

How to properly get rid of this concurrency compile error?

#MainActor
class A {}
class VC: UIViewController {
let foo: A
init() {
self.foo = A() // Error: Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context
super.init(nibName: nil, bundle: nil)
}
#MainActor
init() {
self.foo = A() // Compiles
super.init(nibName: nil, bundle: nil)
}
init(_ void: Void = ()) {
self.foo = A() // Compiles
super.init(nibName: nil, bundle: nil)
}
}
I get that A() should be called on a main-actor initializer, but why the first initializer doesn't inherit the #MainActor from UIViewController? and why the Void parameter gets rid of the error (even with -warn-concurrency)?
Note: if I annotate VC with #MainActor, I get the same error for the super.init in the first initializer, and the third initializer still works.
#MainActor limits all methods and attributes from being assessable from the main thread in the class A.
let foo: A is not the class A it an instance that stores a reference to the class A, you have done nothing to make setting foo thread safe. One of the init of VC is setup to only be executed in the main thread only, where foo is set, but another can be called by any thread and set foo as well.
Edit: Some more info I thought you might find useful
If your sole goal is thread safety, then using MainActor is not a good method, it means only the thread associated with GUI interaction can access your class, which could block some actual code that has to run in the main thread from executing, for just thread safety you are probable better of using actors, they work like classes, but only one thread can be in them at one time, they can be any thread, and different methods can be access by different threads a different times, but only one will be in but actor at a time.
You can also solve the problem by adding an initializer and marking it nonisolated.
#MainActor
class A {
nonisolated init() {}
func load() async -> String {
return "Async!"
}
}

Neither the navigation controller nor its child are deinitialized [duplicate]

In the next code I'm trying to call the deinit method releasing all the references to the Person Class instance Mark but the deinit is never called. Why?
class Person{
let name:String
init(name:String){
self.name = name
println("Person created")
}
deinit {
println("Person \(name) deinit")
}
}
var Mark:Person? = Person(name:"Mark")
Mark = nil // Shouldn't the person deinit method be called here? It doesn't.
Xcode's Playgrounds for Swift don't work like regular apps; they aren't being run just once. The objects created stay in memory and can be inspected until you change the code, at which point the whole playground is reevaluated. When this happens, all previous results are discarded and while all object will be deallocated, you won't see any output from that.
Your code is correct, but Playgrounds is not suited to test things related to memory management.
Here's a related SO question: Memory leaks in the swift playground / deinit{} not called consistently
Deinit will called if create object like this
_ = Person(name:"Mark")
Deinit gets called when you ignore the variable like so.
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
_ = Owner()
PlaygroundPage.current.finishExecution()
Owner class -
public class Owner {
public var car: Car?
public init (_ car: Car? = nil) {
self.car = car
print ("Owner got allocated")
}
deinit {
print ("owner got deallocated")
}
}
// Prints -
Owner got allocated
owner got deallocated
workaround - move all variable initialisation code into a function and call that function.
Playground having issues used to be a problem. For 99% of the memory management cases they work just like a normal project. Playground has improved A LOT over time.
Such a problem should no longer exist and Playground can be used reliably.

Swift, why don't class methods need closure lists

If functions are essentially closures. Why don't methods of a class need closure lists when referencing self or another instance property within the closure.
Is there a [unowned self] behind the scenes? For example:
class MyClass{
func myFunc(){
self.otherFunc()
}
func otherFunc(){
print()
}
}
Wouldn't there be a reference cycle within myFunc? Ie, the closure is pointing to self, and the instance is pointing to the function. Neither could be deallocated.
"If functions are essentially closures." This isn't true. Functions (and methods) are not the same thing as closures. Functions have all their free variables unbound. Closures have bound some or all of their free variables (closed over them, which is where the name "closure" comes from).
A "free variable" is any variable defined outside the scope of the function (including its formal parameters). The top-level function func f(x: Int) has one free variable; when you call it, you must pass a parameter. A closure like { f(1) } has no free variables. When you call it, you do not pass any parameters.
A method, like a function, does not capture anything. It is passed all of its free variables when it is executed. For example, when you make the call object.doThis(), this is the same as calling Type.doThis(object)().
class X {
func doThis() {}
}
let x = X()
x.doThis()
X.doThis(x)() // Same thing
X.doThis(x) is a function that returns a function. There's no magic here. All the free variables are provided during the call. Nothing is captured. (The "free variable" in the case you describe is self, but that doesn't change anything. self is not special, except that it gets a little syntactic sugar around it.)
This is different than a closure:
let c = { x.doThis() }
c()
When I call c(), how does it know the value of x? I may have returned c and x may be out of scope now. The system has to keep track of x (including making a strong reference so it doesn't deallocate), and it does that by capturing it, or "closing over x" which raises the possibility of retain loops. So in c, x is bound. It is not free. You can't pass it when you call c().
self is not special here. It's just another variable. [weak self] in closures isn't special either. You can write [weak x] just as well. The [...] syntax is just the capture list.
Closures may only cause reference cycles when the closure is kept alive. Consider this:
let foo = MyClass()
let bar: () -> () = { in
print(foo)
}
The bar closure holds a reference to foo, but that reference goes away once nothing references bar anymore. For instance:
func f(foo: MyClass) {
let bar: () -> () = { () in
print(foo)
}
}
This does not create a reference cycle, because when f returns, the closure in bar is destroyed. Similarly, when you call myFunc and otherFunc, you do need a strong reference to self (the compiler ensures that you have it), but as you no longer need it at the end of the function, no cycle is created.
In general, a closure will not systematically create a reference cycle, even if it is #escaping. Consider the case of Dispatch.async:
class MyClass {
func foo() {
DispatchQueue.main.async {
print(self)
}
}
}
This does not actually create a reference cycle, because even though the closure references self for a while, self does not reference the closure.
The dangerous case is this one:
class MyClass {
var closure: () -> ()
func f() {
self.closure = {
print(self)
}
}
}
This one actually creates a reference cycle: self.closure has a strong reference to self, and self has a strong reference to self.closure.

Why would removeAllObservers() not work in deinit?

As everyone knows when using the awesomeness that is Firebase in iOS,
whenever you have observations in a view controller,,
var o: DatabaseReference?
var o2: DatabaseReference?
var o3: DatabaseReference?
it's essential that when that screen goes away, you must terminate all the observations...
private func clearObservations() {
print("\n\n clearing observations! \n\n")
if o != nil {
o?.removeAllObservers()
o = nil
}
if o2 != nil {
etc...
}
However!
After considerable testing, you cannot call clearObservations() in deinit - you must call it in viewDidDisappear (or some other logical place).
Again - it explicitly does not work in deinit.
My question, why would it be that actually this does not work in deinit?
BTW, you fire up a Firebase observor like this:
say, viewWillAppear#
o = Database.database().reference(withPath: "string")
o!.observe(.value, with: { (snapshot) in
self.blah(snapshot)
})
I believe your issue is likely that deinit is not being called at all and usually this kind of thing is because your observer closure is strongly retaining self and the closure is itself retained by the firebase service. That means your object can never die. You can break this kind of cycle with an unowned or weak capture.
To check if this is the case, put a print in your deinit. If the print does not get called when you expect then the object is not being released and you should run the memory debugger to see who else is pointing at it.
I've had the same issue before when forgetting to put unowned on a realm observe method.

How memory leak will occur in swift?

I am new to ios development and i want to learn how memory leak will occur in swift or in Objective-C, can any one explain with small example?
Thanks
Small example:
class A {
var b: B!
deinit {
print("deinit of A")
}
}
class B {
var a: A!
deinit {
print("deinit of B")
}
}
do {
let a = A()
let b = B()
a.b = b
b.a = a
}
If you run this code (maybe in Playground), it will print nothing. It means that deinit never called for both objects and they just leaked.
But if you declare one of the properties as weak:
class A {
weak var b: B!
deinit {
print("deinit of A")
}
}
Then deinit will be called and you'll see messages in console.
Edit: add example with closures
Consider this example:
class C {
var f: (Void -> Void)!
deinit {
print("deinit for C")
}
}
do {
let c = C()
c.f = {
print(c)
}
}
c captures f, f captures c. So we got memory leak.
To deal with leaks in closures, you have 2 options – declare that captured object is weak or unowned. Like this:
do {
let c = C()
c.f = { [weak c] in
print(c)
}
}
Basically, you would use weak if it's possible for object to get out of existence and become nil when closure is called; but if you are sure object will still exist at this time, use unowned instead.
After I declare c as weak inside a closure, "deinit for C" is printed – means that everything deallocated successfully.
What this all means for you, the developer?
Almost all the time you don't have to worry about the memory management. It's done for you, automatically. Objects just exist when you need them and vanish when you don't. But there are 2 very common cases when you need to be careful and think about memory.
Delegation. It's common pattern in Cocoa and it could create retain cycles if done wrong. Always declare your delegate as weak unless you have a good reason not to.
Closures. Closure capture references for objects in surrounding scope and does it automatically, without notice. When implementing closure, chech if it will create retain cycle. If yes, declare problem variables as weak or unowned.
For further info I suggest you read official Apple Swift book which can be found in iBooks or here as a website.

Resources