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