我正在关注Swift的教程,我注意到在声明var
变量时,作者使用了let
而不是@IBOutlet
。所以我很好奇为什么我不能使用let
,因为即使对象是常量,对象的属性仍然是可变的,或者不是这样的情况?
使用let
@IBOutlet
属性要求属性是可变的
但我感到困惑,因为questionLabel
是UILabel
对象,不一定是对象的属性。或者questionLabel
对象是当前viewController的属性吗?
import UIKit
class ViewController: UIViewController {
@IBOutlet let questionLabel: UILabel!
}
如果我过度分析,请提前感谢。
答案 0 :(得分:17)
@IBOulet
标记的属性通常是使用界面构建器连接的ViewController的属性。您在界面构建器中创建的视图必须在实际应用程序运行时实际将其中的界面元素连接到属性。
因此,它首先使用 some init
创建一个新的ViewController,而不连接任何接口元素。它们仅在稍后阶段连接。为了使运行时能够在对象创建完成后将属性挂钩到视图元素,它们不能是常量,它们必须是可变的。因为初始化程序完成后它们没有值,所以它们必须是可选项。并且为了不使用之后繁琐的属性,它们是隐式解包的选项,因此您不必编写label!.property
但label.property
就足够了。
这就是为什么当您尝试使用未能连接的IBOutlet
变量执行某些操作时代码崩溃的原因,这也是您无法在初始化程序中使用/更改/操作这些字段的原因。
关于您实际的var
/ let
混淆。是的,可以更改使用let
引用的对象本身,例如text
的{{1}}但是无法更改实际的对象引用。这意味着如果你没有在初始化程序中给常量一个特定的值,它将永远保持UILabel
。
答案 1 :(得分:7)
原因很简单,它不是在初始化期间(在initXXX
方法中)分配,而是在以后加载视图时分配。
编译器实际上甚至无法确定是否已分配变量,因为视图加载是完全动态的。
答案 2 :(得分:5)
在swift中,所有vars和let都可以被视为属性。
如果属性用let
声明,则属性是不可变的(常量)。如果使用var
关键字声明它是可变的(变量)。这是 定义let
和var
之间的差异。
Outlet必须是可变的,因为在初始化对象之前它们的值才会被设置。 (视图控制器已初始化,并且它的网点不会立即加载。)
答案 3 :(得分:2)
您是对的questionLabel
是UILabel
类型的对象,但用作class ViewController
的属性。这就是你@IBOutlet attribute requires property to be mutable
的原因。如果您使用var
,则表示该属性是可变的。如果您使用let
,则表示该属性是不可变的。
尝试在没有@IBOutlet
的情况下创建questionLabel并查看正在进行的操作。也许你可以放在前面。
答案 4 :(得分:1)
首先创建ViewController,然后构建视图树。这意味着当ViewController完成它init
时,这些视图还不存在。它们将在viewDidLoad
之前添加,方法是解析故事板或XIB的类似XML的数据。
我知道这是Apple默认的做事方式,但我总是写下我的网点:
@IBOutlet let questionLabel: UILabel?
由于简单的原因,它绝对没有被证明这个标签在运行时确实存在。例如,在多个屏幕上重复使用ViewControllers时,可能无法设置在设置连接等后更改布局。如果您使用定义为questionLabel
的{{1}},那么UILabel!
您的应用程序将崩溃。我不认为生产中的应用程序应该像那样愚蠢地崩溃。
对于真正的应用程序安全性,确实存在的唯一方法是在代码中构建UI。但是,故事板在一次性屏幕上的易用性非常诱人,我仍然使用它们很多。