iOS lazy var UIBarButtonItem target issue

笑着哭i 提交于 2019-12-07 04:26:36

问题


I found this UIBarButtonItem target issue unconsciously when using lazy var initialization.

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)
  }
}

The printed results showed that barButtonItem1.target was nil, and barButtonItem2.target was self, which seems crazy! I got this issue when i use barButtonItem1's lazy var writing, and then i found that barButtonItem1's action can never be called, and finally the issue was barButtonItem1.target was nil.

I don't know why this happens, however i'm pretty sure this is a bug. Does anyone know something about this? I will really appreciate it if you can explain about it.


回答1:


Explanation below is my guess. And unfortunately, I don't have enough reputation to give a comment so let me give you an answer.

My guess: this is a compiler bug.


First, I crafted a small extension of UIBarButtonItem. (second parameter is not of Any? but 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)
    }
}

Then I tried to initialize the lazy stored variable with the code below.

class ViewController: UIViewController {

    lazy var barButtonItem1 = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))

    override func viewDidLoad() {
        super.viewDidLoad()
        print(barButtonItem1.target)
    }
    func action() { }
}

Then compiler raised error and say

Cannot convert value of type '(NSObject) -> () -> ViewController' to expected argument type 'UIViewController?'

which suggests that compiler failed to determine that self is of ViewController. (The initializer provided by UIKit would compile because the second parameter is of Any? which accepts value of type (NSObject) -> () -> ViewController.)

But when give type annotation to the lazy variable like

lazy var barButtonItem1: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, targetViewController: self, action: #selector(action))

source code happily compiled and barButtonItem1.target was set to self.

I believe the type annotation helped compile. Above is the reason I guess the issue you faced is caused by a compiler bug.


See also: there are reported problems similar to the issue you faced. Both of them are concluded as a compiler bug.

Swift lazy instantiating using self

Type inference when using lazy instantiation



来源:https://stackoverflow.com/questions/43842928/ios-lazy-var-uibarbuttonitem-target-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!