Mert Karakus
Mert Karakus

Reputation: 125

Memory Leak Test

I have a class named PERSON to test memory leak. Here are the contents of class:

let name: String
private var actionClosure: (() -> ())!

init (name: String) {
    self.name = name
    self.actionClosure = {
        println("I am \(self.name)")
    }
}

func performAction () {
    actionClosure()
}

deinit {
    println("\(name) is being deinitialized")
}

Anyway, the book I am following wrote a code inside ViewController.swift. Beneath the viewDidLoad() method. Here are contents:

let person = Person(name: "randomName"); person.performAction();

The part I didn't understand is this: We initialize something with String. I get it but how does the class directly becomes able to use this? Like how does it know to take that init? I really didn't understand what happened there. It would be awesome if someone can explain the class and what happened in it.

Upvotes: 0

Views: 103

Answers (2)

Rob
Rob

Reputation: 438212

Your Person object will leak because you have a "strong reference cycle". The class owns actionClosure (i.e. has a strong reference to it), but actionClosure has a strong reference back to self.

Your closure should use weak or unowned reference to self to break this strong reference cycle:

self.actionClosure = { [unowned self] in 
    println("I am \(self.name)")
}

That will resolve the strong reference cycle.


You asked "how does it know to take that init?" It knows which init to call on the basis of the names and types of the parameters you provide.

Consider your, init implemented as follows:

init (name: String) { ... }

That takes a name parameter of type String. So, to instantiate the object in such a way that it uses that init method, you would use the class name, e.g. Person, with a parameter called name which is of type String, e.g.:

let person = Person(name: "Rob")

See the Initialization chapter of The Swift Programming Language guide.

Upvotes: 1

Andriy Gordiychuk
Andriy Gordiychuk

Reputation: 6272

Inside the Person class you have defined an initialiser which accepts String as the parameter.

init (name: String)

Try adding another initialiser like this

init (name: String) {

    self.name = name

    self.actionClosure = {

        println("I am \(self.name)")

    }

}

init(someOtherName: String) {
    self.name = someOtherName

    self.actionClosure = {

        println("I am \(self.name)")

    }
}

With this you have defined two initialisers and you can call either the original one like

let person = Person(name: "randomName")

or you can call

let person = Person(someOtherName: "randomName")

and they will perform the same initialisation. I hope this answers your question

Upvotes: 1

Related Questions