Reputation: 33
Reading through Advanced Swift and it gives the following example
“In Swift, you can define functions in two ways. One is with the func keyword. The other way is to use a closure expression. Consider this simple function to double a number:
func doubler(i: Int) -> Int {
return i * 2
}
[1, 2, 3, 4].map(doubler) // [2, 4, 6, 8]
And here’s the same function written using the closure expression syntax. Just like before, we can pass it to map:
let doublerAlt = { (i: Int) -> Int in return i*2 }
[1, 2, 3, 4].map(doublerAlt) // [2, 4, 6, 8]”
I was playing around with this and wrote the following code in a collection view cell class.
let setupView = {(label: UILabel) in
addSubview(label)
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
label.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
func setupViews(label: UILabel) {
addSubview(label)
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
label.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
The top one gives me errors but the bottom one using the func keyword works fine. I would think they should both work. I'm wondering if someone might be able to explain.
Upvotes: 2
Views: 59
Reputation: 274730
A closure is closed, so you can't access things outside the closure inside the closure, by default.
self
is something outside the closure, so you need to capture it in order to use it inside the closure. You didn't capture self
, so you can't call self.addSubView
.
self
is kind of a special case. To capture it, you just need to write it out explicitly:
self.addSubView(label)
// and
self.topAnchor
self.leftAnchor
// etc
However, this will cause a retain cycle. The closure holds a strong reference to self
all the time, and self
holds a strong reference to the closure all the time. Neither can be deallocated. Therefore, you should capture self
with unowned
:
lazy var setupView = {[unowned self] (label: UILabel) in
self.addSubview(label)
label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
label.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
label.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
}
Upvotes: 3