首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为什么要创建“隐式解包选项”,因为这意味着您知道有一个值?

为什么要创建“隐式解包选项”,因为这意味着您知道有一个值?
EN

Stack Overflow用户
提问于 2014-06-03 04:09:33
回答 10查看 66.3K关注 0票数 511

为什么要创建一个“隐式非包装可选”而不是只创建一个常规变量或常量?如果您知道可以成功地打开它,那么为什么首先创建一个可选选项呢?例如,为什么:

代码语言:javascript
代码运行次数:0
运行
复制
let someString: String! = "this is the string"

比以下更有用:

代码语言:javascript
代码运行次数:0
运行
复制
let someString: String = "this is the string"

如果“选项表示一个常量或变量被允许具有‘无值’,但”有时从程序的结构中可以清楚地看到,在第一次设置该值之后,可选选项总是有一个值“,那么从一开始将其作为可选值有什么意义呢?如果你知道一个可选的东西总是有一个值,那不是说它不是可选的吗?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2014-06-03 04:15:58

考虑一个对象的情况,它在构造和配置对象时可能具有零属性,但在构造和配置过程中是不可变的和非零的(NSImage通常是这样处理的,尽管在它的情况下,有时变异仍然是有用的)。隐式拆解选项将很好地清理其代码,安全损失相对较低(只要有一个保证,它就安全了)。

(编辑)但要清楚:常规的选项几乎总是更好。

票数 132
EN

Stack Overflow用户

发布于 2014-07-05 05:03:03

在我描述隐式展开选项的用例之前,您应该已经了解了Swift中的选项和隐式未包装选项。如果没有,我建议您先读我关于选拔赛的文章

何时使用隐式未包装的可选选项

有两个主要原因,一个是创建隐式解包装的可选选项。所有这些都与定义一个在nil时永远不会被访问的变量有关,因为否则,Swift编译器将总是强制您显式地打开一个可选的包。

1.在初始化过程中不能定义的常量

每个成员常量必须在初始化完成之前具有一个值。有时,在初始化期间不能用其正确的值初始化一个常量,但仍然可以保证它在被访问之前具有一个值。

使用可选变量可以解决这个问题,因为一个可选变量是用nil自动初始化的,它最终包含的值仍然是不可变的。但是,不断地展开变量可能会带来痛苦,因为您知道这个变量肯定不是零。隐式解包选项实现了与可选选项相同的好处,增加的好处是不必在任何地方显式地展开它。

这方面的一个很好的例子是,在加载视图之前,不能在UIView子类中初始化成员变量:

代码语言:javascript
代码运行次数:0
运行
复制
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.计算迟缓的成员变量

有时,您的成员变量不应为零,但在初始化期间不能将其设置为正确的值。一种解决方案是使用隐式未包装的可选选项,但更好的方法是使用惰性变量:

代码语言:javascript
代码运行次数:0
运行
复制
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的变量,肯定不会有太大的伤害。

票数 464
EN

Stack Overflow用户

发布于 2014-06-03 22:44:37

隐式展开选项对于将属性表示为非可选属性非常有用,而实际上,属性在封面下需要是可选的。这往往是必要的“打结”之间的两个相关的对象,每一个需要参考另一个。当引用实际上都不是可选的时,这是有意义的,但是在初始化对时,其中之一需要为零。

例如:

代码语言:javascript
代码运行次数:0
运行
复制
// 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

不过!这种相互参照的要求往往是紧密耦合和不良设计的标志。如果您发现自己依赖于隐式展开选项,您可能应该考虑重构以消除交叉依赖关系。

票数 56
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24006975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档