强制展开可选的优点是什么?
What is the advantage of force unwrapping an optional?
如果变量是 Optional
强制展开它的优势是什么。
class Button: UIButton {
var title: UILabel? = nil
required init?(coder aDecoder: NSCoder) {
fatalError()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
func addTitle(text: String) {
title = UILabel(frame: CGRect())
self.addSubview(title!)
}
}
let a: Button = Button(frame: CGRect())
a.addTitle("Hello World")
// Case 1
a.title?.text = "Goodbye"
// Case 2
a.title!.text = "Hello World"
问题
在案例 1 我知道它更安全但是是否有任何性能改进或使用理由 案例2?
所以,如果我们知道 案例 1 更安全,我们为什么还要使用 案例2?
根据评论,您的示例实际上无效。抛开这一点:强制展开意味着 "I work only with a concrete value; I want to fail immediately if I don't have one"。因此,通常最好继续执行具有 nil
值的那部分代码,然后在因果关系被大幅削弱后的某个时候遇到其他问题。
因此:它允许您明确谁负责保证值的存在。
一些替代方案(避免强制展开 !
)。使用 a
的 non-nil 值以及当 a
包含 nil
.
时尝试这些
var a: String? = nil
a = "Hello World"
// Case 1 : nil coalescing operator
print(a ?? "a has value nil, let's not unwrap it!")
// Case 2 : if-let clause
if let a = a {
print(a)
}
else {
print("a has value nil, let's not unwrap it!")
}
// Case 3 : guard-let-else clause
func foo(a: String?) {
guard let a = a else {
print("a has value nil, let's not unwrap it!")
return
}
print(a)
}
foo(a)
Performance-wise 强制和可选 binding/chaining 之间可能存在非常小的差异,因为可选版本可能在某处有额外的 if
。
但是尽管如此,当谈到性能问题时,性能瓶颈来自代码的其他部分,例如 non-improved 循环,大量累积 NSNotification
在短时间内发送, UI 等不必要的重绘
因此最好保持安全,使用可选的 binding/casting/chaining 并专注于增加实际性能损失的代码部分。即使在您编写代码时该值保证为 non-nil
,将来情况可能会发生变化,您会突然以您没有预料到的崩溃告终发生。
Swift 使处理可选值变得非常容易,无需编写大量样板代码,您应该利用这些功能。
使用隐式解包 Optional
或使用 !
:
强制解包 Optional
的充分(或至少是合理的)理由
@IBOutlet
s:由于几个原因,这些通常被隐式解包。您不希望每次访问它们时都必须手动打开它们。但更重要的是,如果您的插座连接不正确,您想立即知道。
- 您有意识地决定在值为
nil
时应用程序崩溃的其他情况。例如,如果您从情节提要中实例化一个视图控制器,并且需要它是 UIViewController
的特定子类 MyViewController
才能让您的应用程序正常运行,您可以强制使用return vc as! MyViewController
。这样你马上就会发现不对劲。
老实说,就我所知,就是这样。只是我自己的方法,但我保留 !
用于声明 @IBOutlet
s。否则,99.999% 的时间我在可选链接情况下使用 if let
或 guard
或 ?
解包。还有其他方法可以知道该值为 nil
。如果可选的解包失败,则向控制台打印一条消息,告诉您它失败了。对我来说,一条简短的描述性消息比崩溃和 unexpectedly found nil while unwrapping an optional value
错误更容易调试。如果我想让程序失败,我仍然可以使用 fatalError
和描述性消息:
guard let x = someOptional else { fatalError("someOptional is nil in awakeFromNib.") }
通过将 !
保留 @IBOutlet
秒,每次我遇到其中一个 unexpectedly found nil while unwrapping an optional value
错误时,我都知道在哪里可以找到问题的根源。我在界面生成器中查看我的 @IBOutlet
连接。坚持该政策,并使用其他工具来识别其他 nil
不应该的值,对我有用。
如果变量是 Optional
强制展开它的优势是什么。
class Button: UIButton {
var title: UILabel? = nil
required init?(coder aDecoder: NSCoder) {
fatalError()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
func addTitle(text: String) {
title = UILabel(frame: CGRect())
self.addSubview(title!)
}
}
let a: Button = Button(frame: CGRect())
a.addTitle("Hello World")
// Case 1
a.title?.text = "Goodbye"
// Case 2
a.title!.text = "Hello World"
问题
在案例 1 我知道它更安全但是是否有任何性能改进或使用理由 案例2?
所以,如果我们知道 案例 1 更安全,我们为什么还要使用 案例2?
根据评论,您的示例实际上无效。抛开这一点:强制展开意味着 "I work only with a concrete value; I want to fail immediately if I don't have one"。因此,通常最好继续执行具有 nil
值的那部分代码,然后在因果关系被大幅削弱后的某个时候遇到其他问题。
因此:它允许您明确谁负责保证值的存在。
一些替代方案(避免强制展开 !
)。使用 a
的 non-nil 值以及当 a
包含 nil
.
var a: String? = nil
a = "Hello World"
// Case 1 : nil coalescing operator
print(a ?? "a has value nil, let's not unwrap it!")
// Case 2 : if-let clause
if let a = a {
print(a)
}
else {
print("a has value nil, let's not unwrap it!")
}
// Case 3 : guard-let-else clause
func foo(a: String?) {
guard let a = a else {
print("a has value nil, let's not unwrap it!")
return
}
print(a)
}
foo(a)
Performance-wise 强制和可选 binding/chaining 之间可能存在非常小的差异,因为可选版本可能在某处有额外的 if
。
但是尽管如此,当谈到性能问题时,性能瓶颈来自代码的其他部分,例如 non-improved 循环,大量累积 NSNotification
在短时间内发送, UI 等不必要的重绘
因此最好保持安全,使用可选的 binding/casting/chaining 并专注于增加实际性能损失的代码部分。即使在您编写代码时该值保证为 non-nil
,将来情况可能会发生变化,您会突然以您没有预料到的崩溃告终发生。
Swift 使处理可选值变得非常容易,无需编写大量样板代码,您应该利用这些功能。
使用隐式解包 Optional
或使用 !
:
Optional
的充分(或至少是合理的)理由
@IBOutlet
s:由于几个原因,这些通常被隐式解包。您不希望每次访问它们时都必须手动打开它们。但更重要的是,如果您的插座连接不正确,您想立即知道。- 您有意识地决定在值为
nil
时应用程序崩溃的其他情况。例如,如果您从情节提要中实例化一个视图控制器,并且需要它是UIViewController
的特定子类MyViewController
才能让您的应用程序正常运行,您可以强制使用return vc as! MyViewController
。这样你马上就会发现不对劲。
老实说,就我所知,就是这样。只是我自己的方法,但我保留 !
用于声明 @IBOutlet
s。否则,99.999% 的时间我在可选链接情况下使用 if let
或 guard
或 ?
解包。还有其他方法可以知道该值为 nil
。如果可选的解包失败,则向控制台打印一条消息,告诉您它失败了。对我来说,一条简短的描述性消息比崩溃和 unexpectedly found nil while unwrapping an optional value
错误更容易调试。如果我想让程序失败,我仍然可以使用 fatalError
和描述性消息:
guard let x = someOptional else { fatalError("someOptional is nil in awakeFromNib.") }
通过将 !
保留 @IBOutlet
秒,每次我遇到其中一个 unexpectedly found nil while unwrapping an optional value
错误时,我都知道在哪里可以找到问题的根源。我在界面生成器中查看我的 @IBOutlet
连接。坚持该政策,并使用其他工具来识别其他 nil
不应该的值,对我有用。