Reputation: 125
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
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
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