如何正确解开普通选项和隐式选项?
这个主题似乎很混乱,我只是想了解所有方法以及它们如何有用。
目前有两种创建选项的方法:
var optionalString: String?
var implicitOptionalString: String!
打开两者的方法有哪些?另外,在展开过程中使用
!
和 ?
有什么区别?
有很多相似之处,但也有一些差异。
声明:
var opt: Type?
不安全地展开:
let x = opt!.property // error if opt is nil
安全测试存在性:
if opt != nil { ... someFunc(opt!) ... } // no error
通过绑定安全解开:
if let x = opt { ... someFunc(x) ... } // no error
if let opt { ... someFunc(opt) ... } // no error
安全链接:
var x = opt?.property // x is also Optional, by extension
安全合并零值:
var x = opt ?? nonOpt
声明:
var opt: Type!
不安全地展开(隐式):
let x = opt.property // error if opt is nil
通过赋值不安全地展开:
let nonOpt: Type = opt // error if opt is nil
通过参数传递不安全地展开:
func someFunc(nonOpt: Type) ... someFunc(opt) // error if opt is nil
安全测试存在性:
if opt != nil { ... someFunc(opt) ... } // no error
安全链接:
var x = opt?.property // x is also Optional, by extension
安全合并零值:
var x = opt ?? nonOpt
自 Beta 5 以来,我们还有新的合并运算符 (??):
var a : Int?
let b : Int = a ?? 0
如果可选值为 != nil,则它被展开,否则使用运算符右侧的值
我创建了一种解包可选值的方法:
// MARK: - Modules
import Foundation
import UIKit
import CoreData
// MARK: - PROTOCOL
protocol OptionalType { init() }
// MARK: - EXTENSIONS
extension String: OptionalType {}
extension Int: OptionalType {}
extension Double: OptionalType {}
extension Bool: OptionalType {}
extension Float: OptionalType {}
extension CGFloat: OptionalType {}
extension CGRect: OptionalType {}
extension UIImage: OptionalType {}
extension IndexPath: OptionalType {}
extension Date: OptionalType {}
extension UIFont: OptionalType {}
extension UIColor: OptionalType {}
extension UIViewController: OptionalType {}
extension UIView: OptionalType {}
extension NSMutableDictionary: OptionalType {}
extension NSMutableArray: OptionalType {}
extension NSMutableSet: OptionalType {}
extension NSEntityDescription: OptionalType {}
extension Int64: OptionalType {}
extension CGPoint: OptionalType {}
extension Data: OptionalType {}
extension NSManagedObjectContext: OptionalType {}
prefix operator ?*
//unwrapping values
prefix func ?*<T: OptionalType>( value: T?) -> T {
guard let validValue = value else { return T() }
return validValue
}
您也可以添加自定义数据类型。
用途:-
var myString = ?*str
希望有帮助:)
可选类型意味着变量可能为零。
示例:
var myString: Int? = 55
myString = nil
问号表示它可能具有零值。
但是如果你这样说:
var myString : Int = 55
myString = nil
会显示错误。
现在要检索您需要解开它的值:
print(myString!)
但是如果你想自动解开:
var myString: Int! = 55
然后:
print(myString)
无需拆开包装。希望它会有所帮助。
使用适合工作的正确工具:
guard let
if let
在 Swift 中,有很多方法可以安全地解开可选值。我在上述偏好中订购技术的原因:
let value = optional?.value
if let
对于顺序逻辑来说可能更具可读性。在某些情况下,当我们不想退出函数但继续在展开块之外执行附加逻辑时,if let
比guard
更具可读性。 if let
非常灵活,也可以使用与 guard
语句类似的语法。,
、&&
或 ||
在单个 guard
中检查多个条件。??
。但不要过度使用它们,因为使用 guard
通常可以更清楚地提前退出。if let
和 guard let
的改进语法(在 Swift 5.7 中更加清晰)。!
表示,并且是 iOS 中的反模式,除非是测试套件的一部分,因为如果可选选项是 nil
,它们可能会崩溃。在这种情况下,我们没有利用 Swift 相对于 Objective-C 改进的类型系统。在测试中,我们不关心干净的代码,因为测试不会在生产中运行,并且它们的目的已被包含。if let
和 guard
var x: EnumExample?
if let x {
print(x.rawValue) // No longer optional
}
// We can still explicitly name the `if let` value if we want.
if let value = x {
print(value.rawValue)
}
guard let x else {
return
}
print(x.rawValue) // No longer optional
guard let value = x else {
return
}
print(value.rawValue)
print(x?.rawValue ?? 0) // Unwrap with nil coalescing
注意:我还发现可选链接是展开选项的一种干净替代方案,并且对于我们只需要检查是否存在的情况,使用
x != nil
就足够了。但这超出了 unwrapping 选项的问题范围。
There is only seven ways to unwrap an optional in Swift
var x : String? = "Test"
1,Forced unwrapping — unsafe.
let a:String = x!
2,Implicitly unwrapped variable declaration — unsafe in many cases.
var a = x!
3,Optional binding — safe.
if let a = x {
print("x was successfully unwrapped and is = \(a)")
}
4,Optional chaining — safe.
let a = x?.count
5,Nil coalescing operator — safe.
let a = x ?? ""
6,Guard statement — safe.
guard let a = x else {
return
}
7,Optional pattern — safe.
if case let a? = x {
print(a)
}
您还可以为特定类型创建扩展并使用默认值安全地解包。我做了以下同样的事情:
extension Optional where Wrapped == String {
func unwrapSafely() -> String {
if let value = self {
return value
}
return ""
}
}
使用绑定安全解包的代码示例:
let accountNumber = account.accountNumber //optional
let accountBsb = account.branchCode //optional
var accountDetails: String = "" //non-optional
if let bsbString = account.branchCode, let accString = account.accountNumber {
accountDetails = "\(bsbString) \(accString)" //non-optional
}