var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)
// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}
使用选项
您可以将可选项与 nil 进行比较,以查看它是否具有值:
var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
print("There is a name")
}
if name == nil { // Could also use an "else"
print("Name has no value")
}
这有点令人困惑 . 这意味着可选的是一件事或另一件事 . 它's either nil or it' s "Bob" . 事实并非如此,可选项不会转换为其他内容 . 将它与nil进行比较是制作易于阅读的代码的一种技巧 . 如果可选等于nil,这只意味着枚举当前设置为 .none .
只有选项可以是零
如果您尝试将非可选变量设置为nil,则会出现错误 .
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")
name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.
检查并使用可选项
因为在打开之前你应该总是检查nil并使用可选项,这是一种常见的模式:
var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
let unwrappedMealPreference: String = mealPreference!
print("Meal: \(unwrappedMealPreference)") // or do something useful
}
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
print("Meal: \(unwrappedMealPreference)")
}
这会创建一个临时常量(如果用 var 替换 let ,则为变量),其范围仅在if的大括号内 . 因为必须使用像"unwrappedMealPreference"或"realMealPreference"这样的名称是一种负担,Swift允许您重用原始变量名称,在括号范围内创建一个临时变量名称
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // separate from the other mealPreference
}
这里有一些代码来演示使用不同的变量:
var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"
可选绑定通过检查可选等于nil来工作 . 如果它没有让它沉默:
print("\(mealPreference.debugDescription)")
什么是期权?
Optionals有两个用例:
可能失败的事情(我期待的东西,但我一无所获)
现在什么都不是,但后来可能会出现的事情(反之亦然)
一些具体的例子:
可以存在或不存在的属性,如 Person 类中的 middleName 或 spouse
一种可以返回值或不返回值的方法,例如在数组中搜索匹配项
一种方法,它可以返回结果或获取错误并且不返回任何内容,例如尝试读取文件's contents (which normally returns the file' s数据)但该文件不存在
class Clint: ExpressibleByNilLiteral {
var name: String?
required init(nilLiteral: ()) {
name = "The Man with No Name"
}
}
let clint: Clint = nil // Would normally give an error
print("\(clint.name)")
// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
print("tuxedoRequired is nil")
}
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
print("It's a match!") // Prints "It's a match!"
}
在幕后,Swift在比较之前将非可选项作为可选项包装 . 它也适用于文字( if 23 == numberFromString { )
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)”
// Here is an optional variable:
var age: Int?
// Here is how you would force unwrap it:
var unwrappedAge = age!
如果您强行打开一个可选项并且它等于nil,则可能会遇到此崩溃错误:
这不一定是安全的,所以这里有一个方法可以防止崩溃,以防你不确定类型和值:
方法2和3防止这个问题 .
2)隐式解包可选
if let unwrappedAge = age {
// continue in here
}
注意,unwrapped类型现在是Int,而不是Int? .
3)警卫声明
guard let unwrappedAge = age else {
// continue in here
}
从这里开始,您可以继续使用未包装的变量 . 如果您确定变量的类型,请确保仅强制打开(使用!) .
祝你的项目好运!
476
When i started to learn Swift it was very difficult to realize why optional .
让我们以这种方式思考 . 让我们考虑一个 Person 类,它有两个属性 name 和 company .
class Person: NSObject {
var name : String //Person must have a value so its no marked as optional
var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible
init(name:String,company:String?) {
self.name = name
self.companyName = company
}
}
现在让我们创建一些 Person 的对象
var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil
但是我们无法将 Nil 传递给 name
var personWithNoName:Person = Person.init(name: nil, company: nil)
现在让我们谈谈为什么我们使用 optional? . 让我们考虑一下我们想在公司名称之后添加 Inc 的情况,例如 apple 将是 apple Inc . 我们需要在公司名称和印刷品后追加 Inc .
print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.
现在让我们研究一下为什么可选的选择 .
if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
print(companyString+" Inc") //Will never executed and no crash!!!
}
让我们用 tom 替换 bob
if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
print(companyString+" Inc") //Will never executed and no crash!!!
}
var sampleString: String? ///Optional, Possible to be nil
sampleString = nil ////perfactly valid as its optional
sampleString = "some value" //Will hold the value
if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.
print(value+value) ////Sample String merged into Two
}
sampleString = nil // value is nil and the
if let value = sampleString{
print(value + value) ///Will Not execute and safe for nil checking
}
// print(sampleString! + sampleString!) //this line Will crash as + operator can not add nil
var defaultNil : Int? // declared variable with default nil value
println(defaultNil) >> nil
var canBeNil : Int? = 4
println(canBeNil) >> optional(4)
canBeNil = nil
println(canBeNil) >> nil
println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper
var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4
var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error
12 回答
Swift中的可选项是一种可以保存值或不保存值的类型 . 通过将
?
附加到任何类型来编写选项:Optionals(以及Generics)是最难理解的Swift概念之一 . 由于它们的编写和使用方式,很容易弄清楚它们是什么 . 将上面的可选项与创建普通String进行比较:
从语法看起来,可选的String与普通的String非常相似 . 不是 . 可选的String不是打开某些“可选”设置的String . 它不是一种特殊的String . String和可选String是完全不同的类型 .
这是最重要的事情:可选是一种容器 . 可选的String是一个可能包含String的容器 . 可选的Int是一个可能包含Int的容器 . 将可选项视为一种包裹 . 在打开它之前(或用选项语言“展开”),你不会知道它是否包含任何东西 .
通过在任何Swift文件中键入"Optional"并⌘-单击它,可以在Swift标准库中看到how optionals are implemented . 这是定义的重要部分:
可选只是
enum
,可以是以下两种情况之一:.none
或.some
. 如果它是.some
,则存在一个关联值,在上面的示例中,它将是String
"Hello" . 可选项使用泛型为相关值提供类型 . 可选字符串的类型不是String
,它是Optional
,或者更确切地说是Optional<String>
.Swift对可选项所做的一切都是神奇的,使得阅读和编写代码更加流畅 . 不幸的是,这掩盖了它实际工作的方式 . 我稍后会介绍一些技巧 .
Note: 我'll be talking about optional variables a lot, but it'很好也可以创建可选常量 . 我用它们的类型标记所有变量,以便更容易理解正在创建的类型类型,但您不必在自己的代码中 .
如何创建选项
要创建可选项,请在要包装的类型后附加
?
. 任何类型都是可选的,甚至是您自己的自定义类型 . 您不能在类型和?
之间留出空格 .使用选项
您可以将可选项与
nil
进行比较,以查看它是否具有值:这有点令人困惑 . 这意味着可选的是一件事或另一件事 . 它's either nil or it' s "Bob" . 事实并非如此,可选项不会转换为其他内容 . 将它与nil进行比较是制作易于阅读的代码的一种技巧 . 如果可选等于nil,这只意味着枚举当前设置为
.none
.只有选项可以是零
如果您尝试将非可选变量设置为nil,则会出现错误 .
查看选项的另一种方法是作为普通Swift变量的补充 . 它们是保证具有值的变量的对应物 . 斯威夫特是一种讨厌模糊的语言 . 大多数变量都被定义为非选项,但有时这并不能保证图像变量的值 . 在这种情况下,您必须使其成为可选项 . 它从
nil
开始,当检索到图像时,可选项获取一个值 .使用可选项显示程序员的意图 . 与Objective-C相比,任何对象都可以为零,Swift需要您清楚何时可以丢失值以及何时保证存在 .
要使用可选项,您可以“解开”它
可选的
String
不能用于代替实际的String
. 要在可选内部使用包装值,您必须打开它 . 解包可选项的最简单方法是在可选名称后添加!
. 这叫做"force unwrapping" . 它返回可选内部的值(作为原始类型),但如果可选项是nil
,则会导致运行时崩溃 . 打开之前你应该确定它有 Value .检查并使用可选项
因为在打开之前你应该总是检查nil并使用可选项,这是一种常见的模式:
在这种模式中,您检查是否存在值,然后当您确定它是时,您强制将其打包到临时常量中以供使用 . 因为这是一件很常见的事情,Swift提供了一个使用“if let”的快捷方式 . 这称为“可选绑定” .
这会创建一个临时常量(如果用
var
替换let
,则为变量),其范围仅在if的大括号内 . 因为必须使用像"unwrappedMealPreference"或"realMealPreference"这样的名称是一种负担,Swift允许您重用原始变量名称,在括号范围内创建一个临时变量名称这里有一些代码来演示使用不同的变量:
可选绑定通过检查可选等于nil来工作 . 如果它没有让它沉默:
什么是期权?
Optionals有两个用例:
可能失败的事情(我期待的东西,但我一无所获)
现在什么都不是,但后来可能会出现的事情(反之亦然)
一些具体的例子:
可以存在或不存在的属性,如
Person
类中的middleName
或spouse
一种可以返回值或不返回值的方法,例如在数组中搜索匹配项
一种方法,它可以返回结果或获取错误并且不返回任何内容,例如尝试读取文件's contents (which normally returns the file' s数据)但该文件不存在
委托属性,不一定要设置,通常在初始化后设置
对于类中的
weak
属性 . 他们指向的东西可以随时设置为nil
可能必须释放以回收内存的大型资源
当您需要一种方法来知道何时设置了一个值(数据尚未加载>数据)而不是使用单独的dataLoaded
Boolean
Objective-C中不存在选项,但是有一个等价的概念,返回nil . 可以返回对象的方法可以返回nil . 这被认为意味着"the absence of a valid object"并经常被用来说出错了 . 它仅适用于Objective-C对象,而不适用于基元或基本C类型(枚举,结构) . Objective-C通常有专门的类型来表示缺少这些值(
NSNotFound
,它实际上是NSIntegerMax
,kCLLocationCoordinate2DInvalid
表示无效坐标,-1
或某些负值也被使用) . 编码人员必须了解这些特殊值,因此必须记录并学习每种情况 . 如果方法不能将nil
作为参数,则必须记录 . 在Objective-C中,nil
是一个指针,就像所有对象都被定义为指针一样,但是nil
指向一个特定的(零)地址 . 在Swift中,nil
是一个文字,表示缺少某种类型 .比较为零
您曾经能够使用任何可选的
Boolean
:在更新版本的Swift中,您必须使用
leatherTrim != nil
. 为什么是这样?问题是Boolean
可以包装在一个可选项中 . 如果您有这样的Boolean
:它有两种"false",一种没有值,另一种有值,但值为
false
. Swift讨厌歧义现在你必须经常检查nil
的可选项 .您可能想知道可选
Boolean
的重点是什么?与其他期权一样,.none
状态可能表明该值尚未知 . 网络呼叫的另一端可能有某些东西需要一些时间来轮询 . 可选的布尔也被称为“Three-Value Booleans”Swift技巧
Swift使用一些技巧来允许选项工作 . 考虑这三行普通可选代码;
这些行都不应该编译 .
第一行使用String文字设置可选的String,两种不同的类型 . 即使这是
String
,类型也不同第二行将可选String设置为nil,两种不同的类型
第三行将可选字符串与nil,两种不同类型进行比较
我将介绍允许这些行工作的选项的一些实现细节 .
创建可选项
使用
?
创建一个可选的语法糖,由Swift编译器启用 . 如果你想做很长的事,你可以创建一个像这样的可选项:这称为
Optional
的第一个初始化程序,public init(_ some: Wrapped)
,它从括号内使用的类型推断出可选的关联类型 .创建和设置可选项的更长方法:
将可选设置为nil
您可以创建一个没有初始值的可选项,或者创建一个初始值为
nil
的可选项(两者都具有相同的结果) .协议
ExpressibleByNilLiteral
(以前称为NilLiteralConvertible
)启用允许等于nil
的选项 . 使用Optional
的第二个初始值设定项public init(nilLiteral: ())
创建了可选项 . 文档说你不应该将ExpressibleByNilLiteral
用于除选项之外的任何东西,因为这会改变代码中nil的含义,但是可以这样做:相同的协议允许您将已创建的可选项设置为
nil
. 虽然不推荐,但您可以直接使用nil literal初始化程序:将可选项与nil进行比较
Optionals定义了两个特殊的"=="和"!="运算符,您可以在
Optional
定义中看到它们 . 第一个==
允许您检查是否有任何可选项等于nil . 如果关联类型相同,则设置为.none的两个不同选项将始终相等 . 当你比较nil时,在后面Swift创建一个相同关联类型的可选项,设置为.none然后使用它进行比较 .第二个
==
运算符允许您比较两个选项 . 两者都必须是相同的类型,并且该类型需要符合Equatable
(允许与常规"=="运算符进行比较的协议) . Swift(大概)解开这两个值并直接比较它们 . 它还处理一个或两个选项都是.none
的情况 . 注意与nil
文字比较之间的区别 .此外,它允许您将任何
Equatable
类型与可选包装进行比较:在幕后,Swift在比较之前将非可选项作为可选项包装 . 它也适用于文字(
if 23 == numberFromString {
)我说有两个
==
运算符,但实际上有三分之一允许你把nil
放在比较的左边命名选项
命名可选类型与非可选类型不同,没有Swift约定 . 人们避免在名称中添加内容以显示它是可选的(如“optionalMiddleName”或“possibleNumberAsString”),并让声明显示它是可选类型 . 当你想要命名某些东西以保存可选项中的值时,这会变得很困难 . 名称“middleName”意味着它是一个String类型,因此当您从中提取String值时,通常最终会得到“actualMiddleName”或“unwrappedMiddleName”或“realMiddleName”等名称 . 使用可选绑定并重用变量名来解决此问题 .
官方定义
来自"The Basics" in the Swift Programming Language:
最后,这是1899年关于选项的一首诗:
昨天在楼梯上
我遇到了一个不在那里的男人
他今天不在了
我希望,我希望他能离开
Antigonish
更多资源:
The Swift Programming Guide
Optionals in Swift (Medium)
WWDC Session 402 "Introduction to Swift" (starts around 14:15)
More optional tips and tricks
让我们以
NSError
为例,如果没有't an error being returned you' d想让它可选择返回Nil . 有's no point in assigning a value to it if there isn' t错误..这也允许您拥有默认值 . 因此,如果函数未传递任何内容,则可以将方法设置为默认值
你不能在Swift中有一个指向
nil
的变量 - 没有指针,也没有空指针 . 但是在API中,您通常希望能够指明具体的 Value ,或缺乏 Value - 例如我的窗口有一个代表,如果有,那是谁?可选项是Swift的类型安全,内存安全的方法 .我做了一个简短的回答,总结了上面的大部分内容,以清除我作为初学者的不确定性:
与Objective-C相反,Swift中没有变量可以包含 nil ,因此添加了Optional变量类型(变量后缀为"?"):
最大的区别是Optional变量不直接存储值(正常的Obj-C变量)它们包含 two states :“_
" or " has nil ”:
也就是说,您可以在不同情况下检查这些变量:
通过使用"!"后缀,您还可以访问包含在其中的值 only if those exist . (即它不是 nil ):
这就是你需要使用“?”的原因 . 和“!”并且默认情况下不使用所有这些 . (这是我最大的困惑)
我也同意上面的答案:可选类型不能用作布尔值 .
在目标C中,没有值的变量等于'nil'(也可以使用与n和false相同的'nil'值),因此可以在条件语句中使用变量(具有值的变量与'TRUE'相同'和那些没有 Value 观的人等于'假') .
Swift通过提供“可选值”来提供类型安全性 . 即它可以防止因分配不同类型的变量而形成的错误 .
所以在Swift中,只能在条件语句中提供布尔值 .
在这里,偶数'虽然'hw'是一个字符串,但它不能在if语句中使用,就像在Objective C中一样 .
为此,它需要创建为,
可选值允许您显示缺少值 . 有点像SQL中的NULL或Objective-C中的NSNull . 我想这将是一个改进,因为即使是“原始”类型也可以使用它 .
摘录自:Apple Inc.“The Swift Programming Language . ”iBooks . https://itun.es/gb/jEUH0.l
可选的意思是Swift不完全确定该值是否与类型相对应:例如,Int?意味着Swift并不完全确定该数字是否为Int .
1)如果您完全确定类型,可以使用感叹号强行打开它,如下所示:
如果您强行打开一个可选项并且它等于nil,则可能会遇到此崩溃错误:
这不一定是安全的,所以这里有一个方法可以防止崩溃,以防你不确定类型和值:
2)隐式解包可选
3)警卫声明
从这里开始,您可以继续使用未包装的变量 . 如果您确定变量的类型,请确保仅强制打开(使用!) .
When i started to learn Swift it was very difficult to realize why optional .
让我们以这种方式思考 . 让我们考虑一个
Person
类,它有两个属性name
和company
.现在让我们创建一些
Person
的对象但是我们无法将
Nil
传递给name
现在让我们谈谈为什么我们使用
optional?
. 让我们考虑一下我们想在公司名称之后添加Inc
的情况,例如apple
将是apple Inc
. 我们需要在公司名称和印刷品后追加Inc
.现在让我们研究一下为什么可选的选择 .
让我们用
tom
替换bob
并且 Congratulation! 我们已正确处理
optional?
所以实现点是
我们将变量标记为可选,如果它可能是
nil
如果我们想在代码编译器中的某个地方使用这个变量,它会提醒你,如果它包含
nil
,我们需要检查是否正确处理了该变量 .谢谢......快乐的编码
让我们试试下面的代码 Playground . 我希望能够清楚地知道什么是可选的以及使用它的原因 .
来自https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html:
要更深入地了解,请阅读上面的链接 .
好...
主要区别在于,当optional是nil时,可选链接会正常失败,而当optional可选为nil时,强制解包会触发运行时错误 .
为了反映可以在nil值上调用可选链接的事实,可选链接调用的结果始终是可选值,即使要查询的属性,方法或下标返回非可选值 . 您可以使用此可选返回值来检查可选链接调用是否成功(返回的可选项包含值),或者由于链中的nil值(返回的可选值为nil)而未成功 .
具体来说,可选链接调用的结果与预期返回值的类型相同,但包含在可选中 . 通常返回Int的属性将返回Int?通过可选链接访问时 .
以下是Apple开发者委员会的详细基础教程:Optional Chaining
这是Swift中的等效可选声明:
此声明创建一个名为middleName的String类型的变量 . String变量类型后面的问号(?)表示middleName变量可以包含一个可以是String或nil的值 . 任何查看此代码的人都会立即知道middleName可以为零 . 它是自我记录的!
如果未指定可选常量或变量的初始值(如上所示),则该值将自动设置为nil . 如果您愿意,可以将初始值显式设置为nil:
有关可选阅读下面链接的更多详细信息
http://www.iphonelife.com/blog/31369/swift-101-working-swifts-new-optional-values