Swift,与 UIBarButtonItem 混淆

Posted

技术标签:

【中文标题】Swift,与 UIBarButtonItem 混淆【英文标题】:Swift, confusion with UIBarButtonItem 【发布时间】:2017-07-31 06:05:36 【问题描述】:

我最近开始学习 Swift。当我尝试制作我的第一个 App 时,我对 UIBarButtonItem 感到困惑。如果我把 let UIBarButtonItem 初始化放在 viewDidLoad() 函数之外,当我按下 Next 按钮时什么也不会发生。

class ViewController: UIViewController, UITextFieldDelegate 
    let rightBarButton: UIBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))

    override func viewDidLoad() 
        super.viewDidLoad()
        self.view.backgroundColor = .white

        self.navigationItem.rightBarButtonItem = rightBarButton
    

    func onClickNext(button: UIBarButtonItem) 
        print("should push view controller")
    

但是,当我将initialization 放入viewDidLoad() 函数时,输出区域确实输出了我在onClickNext(button:) 函数中设置的句子

class ViewController: UIViewController, UITextFieldDelegate 
    var rightBarButton: UIBarButtonItem?

    override func viewDidLoad() 
        super.viewDidLoad()

        self.view.backgroundColor = .white

        self.rightBarButton = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))
        self.navigationItem.rightBarButtonItem = rightBarButton
    

    func onClickNext(button: UIBarButtonItem) 
        print("should push view controller")
    

另外,我发现当我将initialization 放在viewDidLoad() 函数之外,并在viewController 中添加UITextField 时,如果我在按下之前触摸textfieldrightBarButton 就会起作用按钮。

这让我很困惑。机制是什么?

【问题讨论】:

非常好的问题 这应该是bug,可以参考这个问题:***.com/questions/43842928/… 【参考方案1】:

好吧,也许您错过了 ViewController 内部的工作方式。

首先,viewDidLoad 是您通常设置或初始化任何视图或视图属性的区域。此方法在视图控制器对象的生命周期内也只调用一次。这意味着self 已经存在。

了解这一点对于了解 let 属性的作用非常重要,(来自 Apple)

常量声明在常量名和初始化表达式的值之间定义了一个不可变绑定;常量的值设置后,就不能再改变了。也就是说,如果一个常量用类对象初始化,对象本身可以改变,但常量名和它引用的对象之间的绑定不能。

尽管上面的区域是你声明变量和常量的地方,通常是为了简单的初始化,它只是告诉 VC 有一个你想要使用的对象并且将有一个类全局范围的区域,但是其余的功能将在视图层次结构加载时添加(意味着对象不依赖于自身,例如,当向按钮添加目标时,您指的是自身内部的方法)....this变量或常量被称为Stored Properties

在最简单的形式中,存储属性是作为特定类或结构的实例的一部分存储的常量或变量。存储属性可以是变量存储属性(由 var 关键字引入)或常量存储属性(由 let 关键字引入)。

最后,你有一个惰性存储属性,也许可以应用到你想要的东西:

惰性存储属性是在第一次使用之前不计算初始值的属性。您可以通过在声明之前编写惰性修饰符来指示惰性存储属性。

解决方案:创建一个惰性 var 存储属性或在 ViewDidLoad 中添加他的属性(当 self 已经存在时)

lazy private var doneButtonItem : UIBarButtonItem = 
    [unowned self] in
    return UIBarButtonItem(title: "Next", style:UIBarButtonItemStyle.Plain, target: self, action: #selector(onClickNext(button:)))
    ()

let rightBarButton: UIBarButtonItem?

override func viewDidLoad() 
        super.viewDidLoad()
        rightBarButton = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))

【讨论】:

谢谢!这解决了我的第一个问题。现在我对第二个问题很好奇:为什么我在按下按钮之前触摸文本字段会起作用? @user5685969 说这可能是一个错误,请参阅问题:***.com/questions/43842928/… 您是否在不设置委托的情况下添加了 UITtexField?您如何通过代码或 xib 添加此控件?这可能是一个错误,但我需要更多信息 我只是添加了 UITextField 而没有通过代码设置它的委托。然后我发现:如果我将 UIBarButtonItem 初始化放在 viewDidLoad() 函数之外,目标操作永远不会起作用,但是在我触摸文本字段后,它会意外地起作用。 我认为这与文本字段的代表无关。我可以通过按下文本字段来解释 ios 如何运行以使目标操作再次起作用。【参考方案2】:
import UIKit


    class ViewController: UIViewController 

        var  btnName = UIButton()



        override func viewDidLoad() 
            super.viewDidLoad()
            btnName.setImage(UIImage(named: "imagename"), for: .normal)
            btnName.frame = CGRect(x:0,y: 0,width: 30,height: 30)
            btnName.addTarget(self, action: #selector(addTargetActionForButton(:_)), for: .touchUpInside)

            let rightBarButton = UIBarButtonItem(customView: btnName)
            self.navigationItem.rightBarButtonItem = rightBarButton

        

        func addTargetActionForButton(_ sender : UIButton)


        
    

【讨论】:

谢谢。但是我知道如何使它工作,我只是混淆了为什么当我将初始化放在 viewDidLoad() 函数之外时它不起作用。【参考方案3】:

您正在将 let 变量从 viewDidLoad 中取出 您不能将 let 全局变量取出。如果你想要让而不是你需要在 viewDidLoad 中声明。更多信息让和 var 检查这个链接What is the difference between `let` and `var` in swift?

 override func viewDidLoad() 

  let rightBarButton: UIBarButtonItem  = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))

    super.viewDidLoad()
    self.view.backgroundColor = .white

    self.navigationItem.rightBarButtonItem = rightBarButton



【讨论】:

我将它设为 var 变量,仍然将初始化放在 viewDidLoad() 函数之外,但它仍然不起作用.. 但是我检查了 let 和 var 对我来说效果很好 不,问题是如果单击文本字段按钮可以正常工作,否则不会【参考方案4】:

UIBatButtonItem 可能包含 UIButton

上面的示例图像有 UINavigationItem,其中包含 LeftBarButtonItems ([UIBarButton]) 和 RightBarButtonItems([UIBarButtonItem]),每个 UIBarButtonItem 都包含 UIButton

我们可以自定义UIButton来指定如何在View中显示 我们可以将按钮操作直接连接到 UIButton

【讨论】:

以上是关于Swift,与 UIBarButtonItem 混淆的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中获取 UIBarButtonItem 的视图

使用 Swift 调整 UIBarButtonItem 的字距

Swift - UIBarButtonItem.customView - 重置为原始状态

以编程方式在Swift中添加UIBarButtonItem操作

旋转 UIBarButtonItem Swift

IOS swift UIBarButtonItem 动作