0xSina
0xSina

Reputation: 21593

Is there a memory issue with this code?

New to Swift and I'm wondering if I have to deal with (potentially) the same issue in this code as I did in Objective-C:

var itemB = EditableItem(title: "Item J")
itemB.onReturn = {(value) in
  var s = itemB.title
  println(value)
}

The closure has a reference to itemB and itemB has a reference to the closure. Does this lead to a cyclic reference and hence a memory leak in Swift or is Swift smart enough to make this a itemB a weak var inside the closure?

If not, how can I fix this?

Upvotes: 1

Views: 42

Answers (1)

Mikael Hellman
Mikael Hellman

Reputation: 2722

No, itemB inside the closure exist only as long as itemB is set outside.

Example, you can test this in a Playground.

Let pretend we have this Class mapping with your example:

Import Foundation
class EditableItem {
  var title = ""
  var onReturn: ((String)->Void)?

  init(title: String) {
    self.title = title
  }

  deinit {
    println("Deinit")
  }
}

And now we run code similar to yours:

// Using optional so that I can set it do nil = will dealloc
var itemB:EditableItem? = EditableItem(title: "Item J")
itemB!.onReturn = {(value) in
  var s = itemB!.title
  println(value)
}

// Execute to make sure anything would retain
itemB!.onReturn!("data")
// var is set to nil, same variable inside the closure
itemB = nil // Deinit will run 

Same example with an variable retaining:

var retainer:EditableItem? = nil

var itemB:EditableItem? = EditableItem(title: "Item J")
itemB!.onReturn = {(value) in
  retainer = itemB!
  println(value)
}

// If onReturn() would not be executed, itemB would not be retained
itemB!.onReturn!("data")
// deinit will not be called
itemB = nil

And example to make the reference weak:

var retainer:EditableItem? = nil

var itemB:EditableItem? = EditableItem(title: "Item J")
// Make sure retainer is weak
itemB!.onReturn = { [weak retainer](value) in
  retainer = itemB!
  println(value)
  // retainer is set here..
}
// retainer is nil here..
itemB!.onReturn!("data")
// retainer is nil here as well..
itemB = nil // And this will deinit

Upvotes: 1

Related Questions