苹果公司的文件如下:
您可以一起使用if和let来处理可能丢失的值。这些值表示为可选项。可选值要么包含值,要么包含nil,表示该值缺失。在值的类型后面写一个问号(?),将该值标记为可选值。
为什么要使用可选值?
苹果公司的文件如下:
您可以一起使用if和let来处理可能丢失的值。这些值表示为可选项。可选值要么包含值,要么包含nil,表示该值缺失。在值的类型后面写一个问号(?),将该值标记为可选值。
为什么要使用可选值?
当前回答
There are lots of errors which are caused by people trying to use a value which is not set, sometime this can cause a crash, in objective c trying to call the methods of a nil object reference would just be ignored, so some piece of your code not executing and the compiler or written code has no way of telling your why. An optional argument let you have variables that can never be nil, and if you try to do build it the compiler can tell you before your code has even had a chance to run, or you can decide that its appropriate for the object to be undefined, and then the compiler can tell you when you try to write something that doesn't take this into account.
在调用nil对象的情况下,你可以直接
object?.doSomthing()
你已经明确地告诉编译器和任何阅读你代码的人,它的可能对象是nil,什么都不会发生。有时,只有在值存在时才希望出现几行代码,因此可以这样做
if let obj = object {
obj.doSomthing()
doSomethingto(obj)
}
这两个语句只会在object是什么东西时执行,简单地说,如果它不是什么东西,你可能想要停止整个代码块的其余部分
guard let obj = object {
return
}
obj.doSomthing()
doSomethingto(obj)
如果后面的所有内容都只适用于object,那么阅读起来会更简单,另一种可能是你想使用默认值
let obj = object ?? <default-object>
obj.doSomthing()
doSomethingto(obj)
现在obj将被赋值给某个对象,即使它是该类型的默认值
选项是有用的情况下一个值可能不会获得一个值,直到一些事件发生或您可以使用一个选项设置为零,以说它不再相关的或者需要设置和使用的一切它没有做任何与它,直到它是集,我喜欢用可选的方法之一是告诉我必须做点什么或者已经完成
func eventFired() {
guard timer == nil else { return }
timer = scheduleTimerToCall(method, in: 60)
}
func method() {
doSomthing()
timer = nil
}
这个sudo代码可以多次调用eventFired,但只有在第一次调用时才会调度一个计时器,一旦调度执行,它会运行一些方法并将计时器设置为nil,这样就可以调度另一个计时器。
一旦你明白了变量处于未定义状态你就可以用它来做任何事情。
其他回答
There are lots of errors which are caused by people trying to use a value which is not set, sometime this can cause a crash, in objective c trying to call the methods of a nil object reference would just be ignored, so some piece of your code not executing and the compiler or written code has no way of telling your why. An optional argument let you have variables that can never be nil, and if you try to do build it the compiler can tell you before your code has even had a chance to run, or you can decide that its appropriate for the object to be undefined, and then the compiler can tell you when you try to write something that doesn't take this into account.
在调用nil对象的情况下,你可以直接
object?.doSomthing()
你已经明确地告诉编译器和任何阅读你代码的人,它的可能对象是nil,什么都不会发生。有时,只有在值存在时才希望出现几行代码,因此可以这样做
if let obj = object {
obj.doSomthing()
doSomethingto(obj)
}
这两个语句只会在object是什么东西时执行,简单地说,如果它不是什么东西,你可能想要停止整个代码块的其余部分
guard let obj = object {
return
}
obj.doSomthing()
doSomethingto(obj)
如果后面的所有内容都只适用于object,那么阅读起来会更简单,另一种可能是你想使用默认值
let obj = object ?? <default-object>
obj.doSomthing()
doSomethingto(obj)
现在obj将被赋值给某个对象,即使它是该类型的默认值
选项是有用的情况下一个值可能不会获得一个值,直到一些事件发生或您可以使用一个选项设置为零,以说它不再相关的或者需要设置和使用的一切它没有做任何与它,直到它是集,我喜欢用可选的方法之一是告诉我必须做点什么或者已经完成
func eventFired() {
guard timer == nil else { return }
timer = scheduleTimerToCall(method, in: 60)
}
func method() {
doSomthing()
timer = nil
}
这个sudo代码可以多次调用eventFired,但只有在第一次调用时才会调度一个计时器,一旦调度执行,它会运行一些方法并将计时器设置为nil,这样就可以调度另一个计时器。
一旦你明白了变量处于未定义状态你就可以用它来做任何事情。
让我们以NSError为例,如果没有返回错误,你会想让返回Nil是可选的。如果没有错误,给它赋值是没有意义的。
var error: NSError? = nil
这也允许您拥有一个默认值。因此,如果函数没有传递任何东西,你可以为方法设置一个默认值
func doesntEnterNumber(x: Int? = 5) -> Bool {
if (x == 5){
return true
} else {
return false
}
}
在Swift中,可选类型既可以有值,也可以没有值。可选选项是通过附加?对任何类型:
var name: String? = "Bertie"
可选项(以及泛型)是Swift中最难理解的概念之一。由于它们的编写和使用方式,很容易对它们有错误的理解。将上面的可选操作与创建普通字符串进行比较:
var name: String = "Bertie" // No "?" after String
从语法上看,它看起来像一个可选的字符串,非常类似于普通的字符串。它不是。一个可选的字符串不是一个打开了一些“可选”设置的字符串。它不是字符串的特殊变种。String和可选String是完全不同的类型。
这里有一件最重要的事情需要知道:可选对象是一种容器。可选String是可能包含String的容器。可选Int型是一个容器,它可能包含一个Int型。可以把可选的东西看作是一种包裹。在你打开它之前(或者在可选语言中“打开”),你不会知道它是否包含一些东西或什么都没有。
通过在任何Swift文件中输入“Optional”并⌘-点击它,您可以看到可选项是如何在Swift标准库中实现的。下面是定义的重要部分:
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
Optional只是一个枚举,可以是两种情况之一:.none或.some。如果它是.some,则有一个相关的值,在上面的例子中,该值将是字符串“Hello”。可选选项使用泛型为关联值指定类型。可选String的类型不是String,而是optional,或者更准确地说optional <String>。
Swift在可选选项上所做的一切都是魔法,让阅读和编写代码更加流畅。不幸的是,这掩盖了它实际工作的方式。我稍后会讲一些技巧。
注意:我将经常谈论可选变量,但也可以创建可选常数。我用它们的类型标记所有变量,以便更容易理解所创建的类型类型,但您不必在自己的代码中这样做。
如何创建可选项
要创建可选对象,请添加?在希望换行的类型之后。任何类型都可以是可选的,甚至是您自己的自定义类型。类型和?之间不能有空格。
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")
}
这有点让人困惑。它意味着可选的东西不是这个就是那个。要么是nil,要么是Bob。这是不对的,可选选项不会转化为其他东西。将它与nil进行比较是一种使代码更易于阅读的技巧。如果一个可选值等于nil,这仅仅意味着枚举当前被设置为。none。
只有可选选项可以为nil
如果你试图将一个非可选变量设置为nil,你会得到一个错误。
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
Another way of looking at optionals is as a complement to normal Swift variables. They are a counterpart to a variable which is guaranteed to have a value. Swift is a careful language that hates ambiguity. Most variables are define as non-optionals, but sometimes this isn't possible. For example, imagine a view controller which loads an image either from a cache or from the network. It may or may not have that image at the time the view controller is created. There's no way to guarantee the value for the image variable. In this case you would have to make it optional. It starts as nil and when the image is retrieved, the optional gets a value.
使用可选对象可以揭示程序员的意图。与Objective-C中任何对象都可以为nil相比,Swift需要你清楚什么时候一个值可以丢失,什么时候它可以保证存在。
要使用可选选项,需要“展开”它
可选的字符串不能用来代替实际的字符串。要在可选对象中使用被包装的值,必须将其展开。展开可选对象的最简单方法是添加一个!在可选名称之后。这就是所谓的“力展开”。它返回可选类型中的值(作为原始类型),但如果可选类型为nil,则会导致运行时崩溃。在展开之前,您应该确保有一个值。
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
}
在此模式中,您将检查一个值是否存在,然后当您确定它存在时,您将强制将其展开为一个临时常数以供使用。因为这是一件很常见的事情,Swift提供了一个使用“if let”的快捷方式。这被称为“可选绑定”。
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。如果没有,它将可选选项解包装到提供的常量中并执行该块。在Xcode 8.3及以后版本(Swift 3.1)中,尝试打印这样的可选选项会导致无用的警告。使用可选参数的debugDescription使其静音:
print("\(mealPreference.debugDescription)")
什么是可选的?
可选项有两个用例:
可能会失败的事情(我一直期待着一些东西,但我什么都没有得到) 现在什么都不是,但以后可能会成为的事情(反之亦然)
一些具体的例子:
A property which can be there or not there, like middleName or spouse in a Person class A method which can return a value or nothing, like searching for a match in an array A method which can return either a result or get an error and return nothing, like trying to read a file's contents (which normally returns the file's data) but the file doesn't exist Delegate properties, which don't always have to be set and are generally set after initialization For weak properties in classes. The thing they point to can be set to nil at any time A large resource that might have to be released to reclaim memory When you need a way to know when a value has been set (data not yet loaded > the data) instead of using a separate dataLoaded Boolean
Optionals don't exist in Objective-C but there is an equivalent concept, returning nil. Methods that can return an object can return nil instead. This is taken to mean "the absence of a valid object" and is often used to say that something went wrong. It only works with Objective-C objects, not with primitives or basic C-types (enums, structs). Objective-C often had specialized types to represent the absence of these values (NSNotFound which is really NSIntegerMax, kCLLocationCoordinate2DInvalid to represent an invalid coordinate, -1 or some negative value are also used). The coder has to know about these special values so they must be documented and learned for each case. If a method can't take nil as a parameter, this has to be documented. In Objective-C, nil was a pointer just as all objects were defined as pointers, but nil pointed to a specific (zero) address. In Swift, nil is a literal which means the absence of a certain type.
与nil的比较
你过去可以使用任意可选类型作为布尔值:
let leatherTrim: CarExtras? = nil
if leatherTrim {
price = price + 1000
}
在最近的Swift版本中,你必须使用leatherTrim != nil。为什么会这样?问题是布尔值可以被包装在可选对象中。如果你有这样的布尔值:
var ambiguous: Boolean? = false
它有两种“假”,一种是没有值,另一种是有值但值为假。Swift讨厌模糊性,所以现在你必须检查一个可选对象是否为nil。
您可能想知道可选布尔值的意义是什么?与其他可选选项一样,.none状态可以指示该值是未知的。在网络呼叫的另一端可能有一些东西需要一些时间进行轮询。可选布尔值也被称为“三值布尔值”
斯威夫特的技巧
Swift使用了一些技巧来允许可选选项工作。考虑这三行看起来普通的可选代码;
var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
这些行都不能编译。
第一行使用String字面值设置了一个可选String,这是两种不同的类型。即使这是一个字符串,类型也是不同的 第二行将可选String设置为nil,这是两种不同的类型 第三行将可选字符串与nil进行比较,这是两种不同的类型
我将详细介绍允许这些行工作的可选选项的一些实现细节。
创建一个可选
使用?创建一个可选的是语法糖,由Swift编译器启用。如果你想从长远来看,你可以创建一个像这样的可选选项:
var name: Optional<String> = Optional("Bob")
这将调用Optional的第一个初始化式public init(_ some: Wrapped),它从括号内使用的类型推断出Optional的关联类型。
创建和设置可选对象的更长的方法:
var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
将一个可选参数设置为nil
你可以创建一个没有初始值的可选对象,也可以创建一个初始值为nil的可选对象(两者具有相同的结果)。
var name: String?
var name: String? = nil
允许可选项等于nil是由协议expressiblebynlitereral(以前称为n文盲可转换)启用的。可选对象是用optional的第二个初始化式public init(nlitereral:())创建的。文档说,你不应该使用expressiblebynilleral的任何东西,除了可选的,因为这会改变你的代码中nil的含义,但它是可能做到的:
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)")
同样的协议允许您将一个已经创建的可选项设置为nil。虽然不建议这样做,但你可以直接使用nil文字初始化式:
var name: Optional<String> = Optional(nilLiteral: ())
将可选对象与nil进行比较
可选选项定义了两个特殊的“==”和“!”="操作符,你可以在Optional定义中看到。第一个==允许你检查任意可选值是否等于nil。如果相关联的类型相同,则两个不同的可选选项设置为.none将始终相等。当你比较nil时,Swift在幕后创建了一个可选的相同关联类型,设置为.none,然后使用它进行比较。
// 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")
}
第二个==操作符允许您比较两个可选选项。两者必须是相同的类型,并且该类型需要符合Equatable(该协议允许使用常规的“==”操作符进行比较)。Swift(推测)将这两个值展开并直接进行比较。它还处理一个或两个可选项都为.none的情况。注意比较和nil字面量之间的区别。
此外,它允许你将任何Equatable类型与可选的封装类型进行比较:
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 {)
我说过有两个==操作符,但实际上还有第三个,允许你把nil放在比较的左边
if nil == name { ... }
命名可选
There is no Swift convention for naming optional types differently from non-optional types. People avoid adding something to the name to show that it's an optional (like "optionalMiddleName", or "possibleNumberAsString") and let the declaration show that it's an optional type. This gets difficult when you want to name something to hold the value from an optional. The name "middleName" implies that it's a String type, so when you extract the String value from it, you can often end up with names like "actualMiddleName" or "unwrappedMiddleName" or "realMiddleName". Use optional binding and reuse the variable name to get around this.
官方定义
摘自Swift编程语言的“基础知识”:
Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development process.
最后,这是一首1899年写的关于可选方案的诗:
昨天在楼梯上 我遇到了一个不在场的男人 他今天又不在那里 我希望,我希望他离开 Antigonish
更多资源:
Swift编程指南 Swift(中)可选选项 WWDC会议402“Swift简介”(14:15开始) 更多可选的提示和技巧
在Swift中,你不能有一个指向nil的变量——既没有指针,也没有空指针。但是在一个API中,你经常希望能够指出一个特定类型的值,或者一个缺乏值的值——例如,我的窗口是否有一个委托,如果有,它是谁?可选的是Swift的类型安全,内存安全的方式来做到这一点。
当我开始学习Swift时,很难意识到为什么是可选的。
让我们这样想。 让我们考虑一个类Person,它有两个属性名和公司。
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!!!
}
咱们把鲍勃换成汤姆吧
if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.
print(companyString+" Inc") //Will executed and no crash!!!
}
和祝贺!我们是否妥善处理可选事宜?
实现要点是
如果一个变量可能为nil,我们将其标记为可选 如果我们想在代码的某个地方使用这个变量,编译器将 提醒你们一下,我们需要检查一下我们是否正确地处理了这个变量 如果它包含nil。
谢谢你!快乐的编码