问题
Why in earlier when we invoke self in a computed property like this example we would need to write lazy var but now we don't have to. why?
let(lazy var in earlier times) pauseButton: UIButton = {
let button = UIButton(type: .system)
let image = UIImage(named: "pause")
button.setImage(image, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.tintColor = .white
button.addTarget(self, action: #selector(handlePause), for: .touchUpInside)
return button
}()
回答1:
I think there is a misunderstanding, which is what you mentioned in the code snippet is not a computed property! it is just a stored property which has been initialized by a closure; As mentioned in the Swift Initialization - Setting a Default Property Value with a Closure or Function:
If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value.
You could check: Difference between computed property and property set with closure.
Note that the closure of pauseButton
will be executed without even using it, if you tried to check it (add a breakpoint in it), you will notice that. I assume this is not what are your expecting -and not what are you aiming to-, so you should declare it as lazy var
instead of let
.
However,
Referring to the same Swift documentation:
If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit
self
property, or call any of the instance’s methods.
Implying that:
class MyViewController: UIViewController {
let btnTitle = "pause"
let pauseButton: UIButton = {
let button = UIButton(type: .system)
let image = UIImage(named: btnTitle)
button.setImage(image, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.tintColor = .white
button.addTarget(self, action: #selector(handlePause), for: .touchUpInside)
return button
}()
func handlePause() { }
}
Will gives an error on the let image = UIImage(named: btnTitle)
:
That should also be applicable for any other instance member, for instance, if you would try to add view.addSubview(button)
into the closure, you will get the same error for view
instance member.
But for a reason (I have no idea why), working with selectors seems to be a special case, because button.addTarget(self, action: #selector(handlePause), for: .touchUpInside)
worked fine for me (Xcode 9.0), nevertheless if you tried to add self
to it, as:
button.addTarget(self, action: #selector(self.handlePause), for: .touchUpInside)
you would get the following error:
来源:https://stackoverflow.com/questions/46794957/self-invocations-in-computed-property