为什么要创建一个“隐式非包装可选”而不是只创建一个常规变量或常量?如果您知道可以成功地打开它,那么为什么首先创建一个可选选项呢?例如,为什么:
let someString: String! = "this is the string"
比以下更有用:
let someString: String = "this is the string"
如果“选项表示一个常量或变量被允许具有‘无值’,但”有时从程序的结构中可以清楚地看到,在第一次设置该值之后,可选选项总是有一个值“,那么从一开始将其作为可选值有什么意义呢?如果你知道一个可选的东西总是有一个值,那不是说它不是可选的吗?
发布于 2014-06-02 20:15:58
考虑一个对象的情况,它在构造和配置对象时可能具有零属性,但在构造和配置过程中是不可变的和非零的(NSImage通常是这样处理的,尽管在它的情况下,有时变异仍然是有用的)。隐式拆解选项将很好地清理其代码,安全损失相对较低(只要有一个保证,它就安全了)。
(编辑)但要清楚:常规的选项几乎总是更好。
发布于 2014-07-04 21:03:03
在我描述隐式展开选项的用例之前,您应该已经了解了Swift中的选项和隐式未包装选项。如果没有,我建议您先读我关于选拔赛的文章
何时使用隐式未包装的可选选项
有两个主要原因,一个是创建隐式解包装的可选选项。所有这些都与定义一个在nil
时永远不会被访问的变量有关,因为否则,Swift编译器将总是强制您显式地打开一个可选的包。
1.在初始化过程中不能定义的常量
每个成员常量必须在初始化完成之前具有一个值。有时,在初始化期间不能用其正确的值初始化一个常量,但仍然可以保证它在被访问之前具有一个值。
使用可选变量可以解决这个问题,因为一个可选变量是用nil
自动初始化的,它最终包含的值仍然是不可变的。但是,不断地展开变量可能会带来痛苦,因为您知道这个变量肯定不是零。隐式解包选项实现了与可选选项相同的好处,增加的好处是不必在任何地方显式地展开它。
这方面的一个很好的例子是,在加载视图之前,不能在UIView子类中初始化成员变量:
class MyView: UIView {
@IBOutlet var button: UIButton!
var buttonOriginalWidth: CGFloat!
override func awakeFromNib() {
self.buttonOriginalWidth = self.button.frame.size.width
}
}
在这里,在视图加载之前不能计算按钮的原始宽度,但您知道在视图上的任何其他方法(初始化除外)之前都会调用awakeFromNib
。与其强制在类中无意义地显式地展开值,还可以将其声明为隐式未包装的可选选项。
2.当应用程序无法从nil
变量中恢复时
这应该是非常罕见的,但是如果当访问变量是nil
时,您的应用程序就不能继续运行,那么费时费力地测试nil
将是浪费时间。通常情况下,如果您的应用程序要继续运行,必须有一个绝对正确的条件,您可以使用assert
。隐式未包装的可选选项中包含了一个assert。即使如此,如果选项为0,那么打开可选的包并使用更具描述性的断言通常是好的。
当不使用隐式未包装的可选选项时
1.计算迟缓的成员变量
有时,您的成员变量不应为零,但在初始化期间不能将其设置为正确的值。一种解决方案是使用隐式未包装的可选选项,但更好的方法是使用惰性变量:
class FileSystemItem {
}
class Directory : FileSystemItem {
lazy var contents : [FileSystemItem] = {
var loadedContents = [FileSystemItem]()
// load contents and append to loadedContents
return loadedContents
}()
}
现在,成员变量contents
直到第一次被访问时才被初始化。这使类在计算初始值之前有机会进入正确的状态。
注:,从上面看,这可能与#1相矛盾。然而,有一个重要的区别有待作出。必须在buttonOriginalWidth
期间设置上述viewDidLoad,以防止任何人在访问属性之前更改按钮宽度。
2.其他地方
在大多数情况下,应该避免隐式未包装选项,因为如果使用错误,当nil
访问时,整个应用程序都会崩溃。如果您不确定变量是否可以为零,请始终默认使用普通可选选项。打开一个从来不是nil
的变量,肯定不会有太大的伤害。
发布于 2014-06-03 14:44:37
隐式展开选项对于将属性表示为非可选属性非常有用,而实际上,属性在封面下需要是可选的。这往往是必要的“打结”之间的两个相关的对象,每一个需要参考另一个。当引用实际上都不是可选的时,这是有意义的,但是在初始化对时,其中之一需要为零。
例如:
// These classes are buddies that never go anywhere without each other
class B {
var name : String
weak var myBuddyA : A!
init(name : String) {
self.name = name
}
}
class A {
var name : String
var myBuddyB : B
init(name : String) {
self.name = name
myBuddyB = B(name:"\(name)'s buddy B")
myBuddyB.myBuddyA = self
}
}
var a = A(name:"Big A")
println(a.myBuddyB.name) // prints "Big A's buddy B"
任何B
实例都应该有一个有效的myBuddyA
引用,所以我们不想让用户将它作为可选的,但是我们需要它是可选的,这样我们就可以在要引用的A
之前构造一个B
。
不过!这种相互参照的要求往往是紧密耦合和不良设计的标志。如果您发现自己依赖于隐式展开选项,您可能应该考虑重构以消除交叉依赖关系。
https://stackoverflow.com/questions/24006975
复制相似问题