iOS lazy var UIBarButtonItem 目标问题
iOS lazy var UIBarButtonItem target issue
我在使用 lazy var 初始化时无意中发现了这个 UIBarButtonItem 目标问题。
class ViewController: UIViewController {
lazy var barButtonItem1 = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(action1))
lazy var barButtonItem2: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(action2))
return barButtonItem
}
override func viewDidLoad() {
super.viewDidLoad()
print(barButtonItem1.target, barButtonItem2.target)
}
}
打印出来的结果是barButtonItem1.target是nil,barButtonItem2.target是self,真是疯了!
我在使用barButtonItem1的lazy var writing时遇到了这个问题,然后我发现barButtonItem1的action永远无法调用,最后问题是barButtonItem1.target was nil.
我不知道为什么会这样,但我很确定这是一个错误。
有人知道这件事吗?如果您能解释一下,我将不胜感激。
下面的解释是我的猜测。不幸的是,我没有足够的声誉来发表评论所以让我给你一个答案。
我的猜测:这是一个编译器错误。
首先,我制作了一个 UIBarButtonItem 的小扩展。 (第二个参数不是Any?
而是UIViewController?
)
extension UIBarButtonItem {
convenience init(barButtonSystemItem systemItem: UIBarButtonSystemItem, targetViewController: UIViewController?, action: Selector?) {
// call the initializer provided by UIKit
self.init(barButtonSystemItem: systemItem, target: targetViewController, action: action)
}
}
然后我尝试用下面的代码初始化惰性存储变量。
class ViewController: UIViewController {
lazy var barButtonItem1 = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))
override func viewDidLoad() {
super.viewDidLoad()
print(barButtonItem1.target)
}
func action() { }
}
然后编译器报错
Cannot convert value of type '(NSObject) -> () -> ViewController' to
expected argument type 'UIViewController?'
这表明编译器未能确定 self
属于 ViewController
。 (UIKit 提供的初始化程序可以编译,因为第二个参数是 Any?
,它接受 (NSObject) -> () -> ViewController
类型的值。)
但是当像
这样的惰性变量给类型注解时
lazy var barButtonItem1: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))
源代码顺利编译,barButtonItem1.target
设置为self
。
我相信类型注释有助于编译。以上是我猜测您遇到的问题是由编译器错误引起的原因。
另请参阅: 报告的问题与您遇到的问题类似。两者都被归结为编译器错误。
Type inference when using lazy instantiation
我在使用 lazy var 初始化时无意中发现了这个 UIBarButtonItem 目标问题。
class ViewController: UIViewController {
lazy var barButtonItem1 = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(action1))
lazy var barButtonItem2: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(action2))
return barButtonItem
}
override func viewDidLoad() {
super.viewDidLoad()
print(barButtonItem1.target, barButtonItem2.target)
}
}
打印出来的结果是barButtonItem1.target是nil,barButtonItem2.target是self,真是疯了! 我在使用barButtonItem1的lazy var writing时遇到了这个问题,然后我发现barButtonItem1的action永远无法调用,最后问题是barButtonItem1.target was nil.
我不知道为什么会这样,但我很确定这是一个错误。 有人知道这件事吗?如果您能解释一下,我将不胜感激。
下面的解释是我的猜测。不幸的是,我没有足够的声誉来发表评论所以让我给你一个答案。
我的猜测:这是一个编译器错误。
首先,我制作了一个 UIBarButtonItem 的小扩展。 (第二个参数不是Any?
而是UIViewController?
)
extension UIBarButtonItem {
convenience init(barButtonSystemItem systemItem: UIBarButtonSystemItem, targetViewController: UIViewController?, action: Selector?) {
// call the initializer provided by UIKit
self.init(barButtonSystemItem: systemItem, target: targetViewController, action: action)
}
}
然后我尝试用下面的代码初始化惰性存储变量。
class ViewController: UIViewController {
lazy var barButtonItem1 = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))
override func viewDidLoad() {
super.viewDidLoad()
print(barButtonItem1.target)
}
func action() { }
}
然后编译器报错
Cannot convert value of type '(NSObject) -> () -> ViewController' to expected argument type 'UIViewController?'
这表明编译器未能确定 self
属于 ViewController
。 (UIKit 提供的初始化程序可以编译,因为第二个参数是 Any?
,它接受 (NSObject) -> () -> ViewController
类型的值。)
但是当像
这样的惰性变量给类型注解时lazy var barButtonItem1: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))
源代码顺利编译,barButtonItem1.target
设置为self
。
我相信类型注释有助于编译。以上是我猜测您遇到的问题是由编译器错误引起的原因。
另请参阅: 报告的问题与您遇到的问题类似。两者都被归结为编译器错误。
Type inference when using lazy instantiation