我知道选项和强制展开的概念,但只是引用iOS 8 Swift Programming Cookbook的示例,我不明白为什么{{1 }} 用来
在示例1中,但在示例2中强制展开var imageView: UIImageView
。希望有人告诉我我在这里缺少什么,所以我知道要阅读什么。
示例1:
var imageView: UIImageView!
示例2:
class ViewController: UIViewController {
let image = UIImage(named: "Safari")
var imageView: UIImageView
required init(coder aDecoder: NSCoder) {
imageView = UIImageView(image: image)
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.center = view.center
view.addSubview(imageView)
}
}
答案 0 :(得分:0)
在示例1中,变量值在init
中设置。在示例2中,变量在稍后初始化并在初始化之后(直到调用viewDidLoad
),其值为nil
。
由于在示例1中变量永远不是nil
,因此它可以是非可选的。但是,在示例2中,变量长时间为nil
,因此它必须是可选变量。
答案 1 :(得分:0)
在swift中,必须在构造函数中初始化所有非可选的类和结构属性,并且没有办法避免这种情况(除非它是内联初始化的,以及它的声明)。
在某些情况下,无法在实例化时初始化非可选属性,因为它取决于同一类的其他属性,或者只是必须在实例生命周期的后期初始化。因此,必须将这些属性声明为可选。
解决方法包括将所有属性声明为隐式解包 - 在内部它们是选项,但它们作为非选项访问(即没有?
运算符)。
这解释了示例1和示例2之间的区别:在前者中,属性在初始化程序中初始化,因此它被声明为非可选项。在后一种情况下,它在viewDidLoad
方法中初始化,因此它被声明为隐式解包。
此模式广泛用于视图和视图控制器出口 - 您会注意到在IB中创建出口时,相应的属性是隐式展开的 - 这是因为变量是在初始化后分配的。
答案 2 :(得分:0)
正如其他人所说,这两个例子的目的是说明在初始化过程中设置的非可选变量与可以在实例化的可选(在这种情况下,是一个隐式解包的变量)之间的区别。稍后一点。
值得注意的是,虽然此示例具有教学价值,但从实际角度来看,在处理视图控制器时,您将使用后一种模式,并在viewDidLoad
中设置可选变量(或者以编程方式创建)视图,您可以使用第三种模式,loadView
方法),而不是第一种在init
中实例化的非可选模式。
我只是想确保你没有离开这个例子,结论是在视图控制器的情况下你应该自由地使用这两种模式中的任何一种。有一些原因与Swift语言无关,而是与视图控制器,视图等生命周期的细节有关,在处理视图控制器时,您会偏好viewDidload
中的可选变量集。
尽管如此,重要的是要理解在什么情况下会在Swift中使用可选项以及在什么情况下不会使用可选项(关键是如果在初始化过程中可能未设置变量,则必须使用可选项)对象),从这个角度来看,这可能是一个有启发性的例子。但请记住,在视图控制器的特定情况下,通常会采用viewDidLoad
模式。
答案 3 :(得分:0)
示例1的唯一初始化程序是required init(coder aDecoder: NSCoder)
,它始终将值赋予imageView
。因此,imageView
将在启动后始终具有值。
示例2没有或不需要initilizer,因为两个存储的属性在其声明中都有一个初始值:
let image = UIImage(named: "Safari") // has an initial value of whatever UIImage(named: "Safari") returns
var imageView: UIImageView! // has an initial value of nil
因此,您可以通过调用swift自动添加的初始化程序来构造ViewController
:ViewController()
这会导致imageView
的值为nil
。