swift变量

1. swift的基本变量类型

 swift 的变量类型和OC、C基本相似,int = 整形, double = 双精度浮点 , float = 单精度浮点, string = 字符串, bool = 布尔值,

swift中一行结束不需要使用 ; ,但是如果两句代码写到同一行,就需要用 ; 隔开

2.swift属性声明

和OC不同,swift的属性分为变量和常量,用let 声明常量,用var声明变量,常量的值不可更改。

属性注释

  1. var welcomeMessage: String 

如上代码, : 表示的是属性类型,上面声明的是一个 String类型的变量,变量名是welcomeMessage 

welcomeMessage只能赋值为字符串。

也可以定义多个相同类型的属性,中间用逗号隔开

  1. var red, green, blue: Double

如上,定义了三个 Double类型的变量。

swift有变量类型推导,所以基本上不用定义类型,比如

      var text = 10   

这时text就是int类型的。

变量名可以包括任意字符,甚至Unicode,和汉语,常量和变量名称不能包含空白字符,数学符号,箭头,专用(或无效)Unicode代码点或线条和框图字符。也不能以数字开头,尽管数字可能包含在名字的其他地方。

一旦声明了某个类型的常量或变量,就不能再声明它的名字,或者改变它来存储不同类型的值。你也不能把一个常量变成一个变量或一个常量变量。

 

打印函数为Print()

print(_:separator:terminator:)函数是一个全局函数,它将一个或多个值打印到适当的输出。例如,在Xcode中,该print(_:separator:terminator:)函数在Xcode的“控制台”窗格中输出其输出。separatorterminator参数都有默认值,所以当你调用这个函数,你可以忽略它们。默认情况下,函数通过添加换行符来终止打印的行。要打印一个没有换行符的值,传递一个空字符串作为终止符 - 例如print(someValue, terminator: "")

 

Swift使用字符串插值将常量或变量的名称作为占位符包含在较长的字符串中,并提示Swift将其替换为该常量或变量的当前值。用圆括号将名称包装起来,并在左括号之前用反斜杠进行转义:

  1. print("The current value of friendlyWelcome is \(friendlyWelcome)")
  2. // Prints "The current value of friendlyWelcome is Bonjour!"

注意

你可以用串插中使用的所有选项中描述字符串插值

注释

使用注释在代码中包含不可执行的文本,作为注释或提醒。在编译代码时,Swift编译器会忽略注释。

Swift中的注释与C中的注释非常相似。单行注释以两个正斜杠(//开头

  1. // This is a comment.

多行注释以正斜杠开始,后跟星号(/*),以星号结尾,后跟正斜杠(*/):

  1. /* This is also a comment
  2. but is written over multiple lines. */

与C中的多行注释不同,Swift中的多行注释可以嵌套在其他多行注释中。您可以通过启动多行注释块,然后在第一个块内开始第二个多行注释来编写嵌套注释。然后关闭第二个块,然后关闭第一个块:

  1. /* This is the start of the first multiline comment.
  2. /* This is the second, nested multiline comment. */
  3. This is the end of the first multiline comment. */

嵌套的多行注释使您能够快速轻松地注释大量代码,即使代码已经包含多行注释。

分号

与许多其他语言不同,Swift不需要;在代码中的每个语句之后都写一个分号(),尽管如果你愿意的话可以这样做。但是,如果要在一行中编写多个单独的语句需要使用分号

  1. let cat = "🐱"; print(cat)
  2. // Prints "🐱"

整型

整数是没有小数部分的整数,如42-23整数有符号(正数,零或负数)或无符号数(正数或零)。

Swift提供了8,16,32和64位格式的有符号和无符号整数。这些整数遵循类似于C的命名约定,其中8位无符号整数是类型的UInt8,32位有符号整数是类型的Int32像Swift中的所有类型一样,这些整数类型都有大写的名字。

整数界限

你可以用它来访问每个整数类型的最小值和最大值minmax特性:

  1. let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
  2. let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8

这些属性的值是适当大小的数字类型(UInt8例如上面的示例中),因此可以在表达式中与其他相同类型的值一起使用。

诠释

在大多数情况下,您不需要选择要在代码中使用的特定大小的整数。Swift提供了一个额外的整数类型,Int它与当前平台的本地字大小大小相同:

  • 在一个32位平台上,Int尺寸与Int32

  • 在64位平台上,Int尺寸与Int64

除非需要使用特定大小的整数,否则请Int在代码中使用整数值。这有助于代码的一致性和互操作性。即使在32位平台上,Int也可以存储-2,147,483,648之间的任意值2,147,483,647,并且对于很多整数范围来说足够大。

UINT

Swift还提供了一个无符号整数类型,UInt它的大小与当前平台的本地字大小相同:

  • 在一个32位平台上,UInt尺寸与UInt32

  • 在64位平台上,UInt尺寸与UInt64

注意

UInt仅在您特别需要与平台的本机字大小相同的无符号整数类型时才使用如果不是这种情况,Int即使要知道存储的值是非负的也是优选的。Int整数值的一致使用有助于代码的互操作性,避免了在不同数字类型之间进行转换的需要,并匹配整数类型推断,如类型安全和类型推断中所述

浮点数字

浮点数是具有小数部分的数字,例如3.141590.1,和-273.15

浮点类型可以表示比整数类型更广泛的数值范围,并且可以存储比可以存储在数组中更大或更小的数字IntSwift提供了两个有符号的浮点数类型:

  • Double 代表一个64位的浮点数。

  • Float 表示一个32位的浮点数。

注意

Double具有至少15位十进制数的精度,而精度Float可以小至6位十进制数。要使用适当的浮点类型取决于您需要在代码中使用的值的性质和范围。在任何类型都适合的情况下,Double是首选。

类型安全和类型推断

Swift是一个类型安全的语言。类型安全的语言鼓励你清楚你的代码可以使用的值的类型。如果你的代码的一部分需要一个String,你不能Int错误地通过它

因为Swift是类型安全的,所以它在编译代码时执行类型检查,并将任何不匹配的类型标记为错误。这使您能够在开发过程中尽早捕获并修复错误。

类型检查有助于避免在使用不同类型的值时发生错误。但是,这并不意味着你必须指定你声明的每个常量和变量的类型。如果你不指定你需要的值的类型,Swift使用类型推断来计算出适当的类型。类型推断使编译器能够在编译代码时自动推断特定表达式的类型,只需检查您提供的值即可。

由于类型推理,与C或Objective-C等语言相比,Swift所需的类型声明要少得多。常量和变量仍然是明确的类型,但是很多指定类型的工作都是为你完成的。

当你用一个初始值声明一个常量或变量时,类型推断特别有用。这通常是通过在声明它的点处为常量或变量赋予一个文字值(或文字)来完成的。(A字面值是直接出现在源代码中,如一个值423.14159在下面的例子。)

例如,如果你将一个42新的常量赋值给一个新的常量,而没有说明它是什么类型的话,那么Swift推断你想让这个常量成为一个常量Int,因为你用一个看起来像一个整数的数字来初始化它:

  1. let meaningOfLife = 42
  2. // meaningOfLife is inferred to be of type Int

同样,如果你没有为浮点数指定一个类型,Swift会推断你想创建一个Double

  1. let pi = 3.14159
  2. // pi is inferred to be of type Double

当推断浮点数的类型时, Swift总是选择Double(而不是Float)。

如果在表达式中结合整数和浮点文字,Double将从上下文中推断出一种类型

  1. let anotherPi = 3 + 0.14159
  2. // anotherPi is also inferred to be of type Double

字面值3没有明确的类型本身,所以Double从浮点文字的存在推断出适当的输出类型作为加法的一部分。

数字文字

整数文字可以写成:

  • 一个十进制数,没有前缀

  • 一个二进制数字,带有0b前缀

  • 一个八进制数,有0o前缀

  • 一个十六进制数,有0x前缀

所有这些整数文字都有一个十进制值17

  1. let decimalInteger = 17
  2. let binaryInteger = 0b10001 // 17 in binary notation
  3. let octalInteger = 0o21 // 17 in octal notation
  4. let hexadecimalInteger = 0x11 // 17 in hexadecimal notation

浮点文字可以是十进制(不带前缀)或十六进制(带0x前缀)。它们必须在小数点的两侧始终有一个数字(或十六进制数字)。十进制浮点数也可以有一个可选的指数,用大写或小写表示e十六进制浮点数必须有一个指数,用大写或小写表示p

对于指数为的十进制数exp,基数乘以10 exp

  • 1.25e2意味着1.25 x 10 2,或125.0

  • 1.25e-2意味着1.25 x 10 -2,或者0.0125

对于指数为的十六进制数exp,基数乘以2 exp

  • 0xFp2指15 x 2 2,或60.0

  • 0xFp-2指的是15 x 2 -2,或者3.75

所有这些浮点文字都有十进制值12.1875

  1. let decimalDouble = 12.1875
  2. let exponentDouble = 1.21875e1
  3. let hexadecimalDouble = 0xC.3p0

数字文字可以包含额外的格式,以方便阅读。整数和浮点数都可以用额外的零填充,并且可以包含下划线来帮助提高可读性。这两种格式都不影响字面值的基础值:

  1. let paddedDouble = 000123.456
  2. let oneMillion = 1_000_000
  3. let justOverOneMillion = 1_000_000.000_000_1

数字类型转换

Int在代码中 使用所有通用整数常量和变量类型,即使它们已知是非负的。在日常情况下使用默认的整数类型意味着整型常量和变量可以在您的代码中立即互操作,并且将与整型文字值的推断类型相匹配。

仅当手头任务特别需要使用其他整数类型时,才能使用其他整数类型,这是因为来自外部源的显式大小的数据,或性能,内存使用情况或其他必要的优化。在这些情况下使用明确大小的类型有助于捕获任何意外的值溢出,并隐含地记录正在使用的数据的性质。

整数转换

可以存储在整数常量或变量中的数字范围对于每种数字类型都是不同的。一个Int8常数或变量可以存储之间的数字-128127,而UInt8常数或变量可以存储之间的数字0255在编译代码时,不能将其放入常量或变量的大小的整数类型中会报告为错误:

  1. let cannotBeNegative: UInt8 = -1
  2. // UInt8 cannot store negative numbers, and so this will report an error
  3. let tooBig: Int8 = Int8.max + 1
  4. // Int8 cannot store a number larger than its maximum value,
  5. // and so this will also report an error

由于每种数字类型都可以存储不同范围的值,因此您必须逐个选择数字类型转换。这种选择加入方法可以防止隐藏的转换错误,并有助于在代码中明确类型转换意图。

要将一个特定的号码类型转换为另一个号码类型,您需要使用现有的值初始化一个所需类型的新号码。在下面的例子中,常量twoThousand是类型的UInt16,而常量one是类型的UInt8他们不能直接加在一起,因为他们不是同一类型的。相反,这个例子调用UInt16(one)创建一个新UInt16one,并用这个值代替原来的值:

  1. let twoThousand: UInt16 = 2_000
  2. let one: UInt8 = 1
  3. let twoThousandAndOne = twoThousand + UInt16(one)

因为添加的两边都是现在的类型UInt16,所以允许添加。输出常量(twoThousandAndOne)被推断为是类型的UInt16,因为它是两个UInt16的总和

SomeType(ofInitialValue)是调用Swift类型的初始值设定项并传入初始值的默认方式。在幕后,UInt16有一个接受一个UInt8的初始化器,所以这个初始化器被用来UInt16从现有的一个新UInt8你不能在这里传入任何类型,但是它必须是一个UInt16提供初始化的类型扩展现有类型以提供接受新类型(包括您自己的类型定义)的初始化方法在扩展中介绍

整数和浮点转换

整数和浮点数字类型之间的转换必须明确:

  1. let three = 3
  2. let pointOneFourOneFiveNine = 0.14159
  3. let pi = Double(three) + pointOneFourOneFiveNine
  4. // pi equals 3.14159, and is inferred to be of type Double

在这里,常量的值three被用来创建一个新的类型值Double,所以添加的两边是相同的类型。如果没有这个转换,不允许增加。

浮点到整数转换也必须明确。整数类型可以使用DoubleFloat来初始化

  1. let integerPi = Int(pi)
  2. // integerPi equals 3, and is inferred to be of type Int

当用这种方式初始化一个新的整数值时,浮点值总是被截断的。这意味着4.75变成4-3.9变成-3

注意

数字常量和变量的组合规则与数字文字的规则不同。字面值3可以直接添加到文字值0.14159,因为数字文字本身没有明确的类型。只有在编译器评估它们的时候才推断它们的类型。

类型别名

类型别名为现有类型定义了一个替代名称。您可以使用typealias关键字定义类型别名

如果要通过上下文更合适的名称引用现有类型,例如在从外部源处理特定大小的数据时,类型别名很有用:

  1. typealias AudioSample = UInt16

一旦你定义了一个类型别名,你可以在任何你可能使用原始名称的地方使用别名:

  1. var maxAmplitudeFound = AudioSample.min
  2. // maxAmplitudeFound is now 0

这里AudioSample被定义为一个别名UInt16因为它是一个别名,AudioSample.min实际调用的调用UInt16.min,它提供0maxAmplitudeFound变量的初始值

布尔

Swift有一个基本的布尔类型,叫做Bool布尔值被称为逻辑,因为它们只能是真或假。Swift提供了两个布尔常量值,true并且false

  1. let orangesAreOrange = true
  2. let turnipsAreDelicious = false

根据它们用布尔文字值初始化的事实推断了这些类型orangesAreOrangeturnipsAreDelicious已经被推断出来Bool正如IntDouble上面,你并不需要声明常量或变量Bool,如果将其设置为truefalse为您创建它们尽快。类型推断有助于使Swift代码在使用其他已知类型的值初始化常量或变量时更加简洁易读。

当您使用条件语句(如if语句)时,布尔值特别有用

  1. if turnipsAreDelicious {
  2. print("Mmm, tasty turnips!")
  3. } else {
  4. print("Eww, turnips are horrible.")
  5. }
  6. // Prints "Eww, turnips are horrible."

控制流程if中更详细地介绍了 诸如声明等条件语句

Swift的类型安全性可以防止非布尔值被替换Bool以下示例报告编译时错误:

  1. let i = 1
  2. if i {
  3. // this example will not compile, and will report an error
  4. }

但是,下面的替代示例是有效的:

  1. let i = 1
  2. if i == 1 {
  3. // this example will compile successfully
  4. }

i == 1比较 的结果是类型的Bool,所以这个第二个例子通过类型检查。比较像i == 1基本操作符中讨论

就像Swift中的其他类型安全例子一样,这种方法避免了意外错误,并确保特定代码段的意图总是清晰的。

元组

组将多个值组合为一个复合值。元组中的值可以是任何类型,不必是彼此相同的类型。

在这个例子中,(404, "Not Found")是一个描述HTTP状态码的元组每当您请求网页时,HTTP状态码都是由Web服务器返回的特殊值。404 Not Found如果您请求不存在的网页,则会返回状态代码

  1. let http404Error = (404, "Not Found")
  2. // http404Error is of type (Int, String), and equals (404, "Not Found")

这个(404, "Not Found")元组将an Int和a 分组在一起String,为HTTP状态码提供了两个独立的值:一个数字和一个人类可读的描述。它可以被描述为“一个类型的元组(Int, String)”。

你可以从任何类型的排列中创建元组,并且可以包含尽可能多的不同类型。没有什么阻止你有型的元组(Int, Int, Int),或者(String, Bool),或者你确实需要的任何其他排列。

你可以一个元组的内容分解成单独的常量或变量,然后像往常一样访问:

  1. let (statusCode, statusMessage) = http404Error
  2. print("The status code is \(statusCode)")
  3. // Prints "The status code is 404"
  4. print("The status message is \(statusMessage)")
  5. // Prints "The status message is Not Found"

如果您只需要某些元组的值,则_在分解元组时,请使用下划线(忽略部分元组:

  1. let (justTheStatusCode, _) = http404Error
  2. print("The status code is \(justTheStatusCode)")
  3. // Prints "The status code is 404"

或者,使用从零开始的索引号访问元组中的各个元素值:

  1. print("The status code is \(http404Error.0)")
  2. // Prints "The status code is 404"
  3. print("The status message is \(http404Error.1)")
  4. // Prints "The status message is Not Found"

当定义元组时,可以将元组中的各个元素命名为:

  1. let http200Status = (statusCode: 200, description: "OK")

如果您将元素命名为元组,则可以使用元素名称来访问这些元素的值:

  1. print("The status code is \(http200Status.statusCode)")
  2. // Prints "The status code is 200"
  3. print("The status message is \(http200Status.description)")
  4. // Prints "The status message is OK"

元组作为函数的返回值特别有用。尝试检索网页的函数可能会返回(Int, String)元组类型来描述页面检索的成功或失败。通过返回具有两个不同类型的值的元组,每个不同类型的函数都提供了有关其结果的更多有用信息,而不是仅返回单个类型的单个值。有关更多信息,请参阅具有多个返回值的函数

注意

元组对于相关值的临时组是有用的。它们不适合创建复杂的数据结构。如果您的数据结构可能会持续超出临时范围,则将其建模为类或结构,而不是元组。有关更多信息,请参阅类和结构

选配

在价值可能不存在的情况下 使用可选项可选的代表两种可能性:要么有一个值,你可以解开可选的访问值,或者有没有价值可言。

注意

C或Objective-C中不存在可选项的概念。Objective-C中最接近的东西是nil从一个方法返回的能力,否则返回一个对象,nil意思是“缺少一个有效的对象”。但是,这只适用于对象 - 它不适用于结构,基本C类型或枚举值。对于这些类型,Objective-C方法通常会返回一个特殊值(如NSNotFound)来指示缺少值。这种方法假设方法的调用者知道有一个特殊的值来测试,并记得检查它。Swift的选项可以让你指出没有任何类型的值,而不需要特殊的常量。

以下是如何使用可选项来应对价值缺失的一个例子。Swift的Int类型有一个初始化器,它试图将一个String值转换成一个Int值。但是,并不是每个字符串都可以转换成一个整数。该字符串"123"可以转换为数字值123,但字符串"hello, world"没有明显的数值转换。

下面的例子使用初始化器来尝试将a String转换为Int

  1. let possibleNumber = "123"
  2. let convertedNumber = Int(possibleNumber)
  3. // convertedNumber is inferred to be of type "Int?", or "optional Int"

因为初始化器可能失败,所以它返回一个可选的 Int,而不是一个Int可选Int是写成Int?,而不是Int问号表示它所包含的值是可选的,这意味着它可能包含一些 Int值,或者它可能根本不包含任何值(它不能包含任何其他的东西,比如Bool值或String值,它可以是一个Int,或者什么也不是。)

通过给可选变量赋予一个特殊值来设置一个可选变量nil

  1. var serverResponseCode: Int? = 404
  2. // serverResponseCode contains an actual Int value of 404
  3. serverResponseCode = nil
  4. // serverResponseCode now contains no value

注意

你不能使用nilnonoptional常量和变量。如果代码中的某个常量或变量需要在某些条件下没有值的情况下工作,则始终将其声明为适当类型的可选值。

如果您定义了一个可选变量而不提供默认值,则会自动nil为您设置该变量

  1. var surveyAnswer: String?
  2. // surveyAnswer is automatically set to nil

注意

Swift nilnilObjective-C 不一样在Objective-C中,nil是一个指向不存在对象的指针。在Swift中,nil不是一个指针,而是缺少某种类型的值。选配的任何类型可以设置为nil,不只是对象类型。

如果陈述和强制解包

您可以使用if语句通过比较可选的against来确定可选是否包含值nil您使用“等于”运算符(==)或“不等于”运算符(!=执行此比较

如果可选值有一个值,则认为它是“不等于” nil

  1. if convertedNumber != nil {
  2. print("convertedNumber contains some integer value.")
  3. }
  4. // Prints "convertedNumber contains some integer value."

一旦确定可选的确实包含一个值,就可以通过!在可选名称的末尾添加一个感叹号()来访问其基础值感叹号有效地说:“我知道这个可选肯定有价值,请使用它“。这被称为强制展开可选的值:

  1. if convertedNumber != nil {
  2. print("convertedNumber has an integer value of \(convertedNumber!).")
  3. }
  4. // Prints "convertedNumber has an integer value of 123."

有关详情if,请参阅控制流程

注意

尝试使用!访问不存在的可选值触发运行时错误。nil在使用!强制解开其值之前,请确保可选包含非值。

可选的绑定

您使用可选绑定来查找可选是否包含值,如果是,则使该值可用作临时常量或变量。可选的绑定可以ifwith while语句一起用来检查一个可选的值,并把这个值提取到一个常量或变量中,作为单个动作的一部分。ifwhile控制流程中更详细地描述报表

if语句编写一个可选的绑定,如下所示:

  • 如果 constantName = someOptional {
  •     声明
  • }

您可以重写Optionals部分中possibleNumber示例以使用可选绑定而不是强制展开:

  1. if let actualNumber = Int(possibleNumber) {
  2. print("\"\(possibleNumber)\" has an integer value of \(actualNumber)")
  3. } else {
  4. print("\"\(possibleNumber)\" could not be converted to an integer")
  5. }
  6. // Prints ""123" has an integer value of 123"

这段代码可以读作:

“如果Int返回的可选Int(possibleNumber)值包含一个值,则设置一个新的常量调用actualNumber可选值中包含的值。”

如果转换成功,则该actualNumber常量在if语句的第一个分支内可用它已经被包含可选项中的值初始化,所以不需要使用!后缀来访问它的值。在这个例子中,actualNumber只是用来打印转换的结果。

您可以使用可选绑定的常量和变量。如果您想操作语句actualNumber第一个分支内的值if,您可以if var actualNumber改为写入,并且可选内容中的值将作为变量而不是常量提供。

您可以根据需要在单个if语句中包含尽可能多的可选绑定和布尔条件,并用逗号分隔。如果可选绑定中的nil任何值或任何布尔条件的计算结果false,则整个if语句的条件被认为是false以下if声明是等同的:

  1. if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
  2. print("\(firstNumber) < \(secondNumber) < 100")
  3. }
  4. // Prints "4 < 42 < 100"
  5. if let firstNumber = Int("4") {
  6. if let secondNumber = Int("42") {
  7. if firstNumber < secondNumber && secondNumber < 100 {
  8. print("\(firstNumber) < \(secondNumber) < 100")
  9. }
  10. }
  11. }
  12. // Prints "4 < 42 < 100"

注意

if语句中使用可选绑定创建的常量和变量只能在if语句的主体中使用相反,使用guard语句创建的常量和变量可以在语句之后的代码行中找到guard,如Early Exit中所述

隐含解包选项

如上所述,可选项表示常数或变量被允许具有“无值”。可以使用if语句来检查选项,以查看是否存在值,并且可以使用可选绑定有条件地解包,以访问可选值(如果存在)。

有时从程序的结构中可以清楚地看到,在第一次设置值之后,可选项将始终有一个值。在这些情况下,每次访问时都不需要检查和打开可选的值,因为可以安全地假定所有的时间都有一个值。

这些选项被定义为隐含的解包选项你写一个隐式解开的可选项,在你想要的可选类型之后放置一个感叹号(String!)而不是一个问号(String?)。

当一个可选的值被确认在第一次定义的可选值之后立即存在时,隐式解包的可选值是有用的,并且可以肯定地假定在随后的每个点都存在。Swift中隐式解包选项的主要用途是在类初始化期间,如Unowned References和Unwinedly Unwrapped Optional Properties中所述

隐式解包可选是幕后的普通可选项,但也可以像非可选值一样使用,而不必在每次访问时展开可选值。以下示例显示了在以可显式方式访问包装值时,可选字符串与隐式解包的可选字符串之间的行为差​​异String

  1. let possibleString: String? = "An optional string."
  2. let forcedString: String = possibleString! // requires an exclamation mark
  3. let assumedString: String! = "An implicitly unwrapped optional string."
  4. let implicitString: String = assumedString // no need for an exclamation mark

你可以想象一个隐式解包的可选方法,只要使用它就可以自动解包这个可选方法。每次使用时,不要在可选名称后面放置感叹号,而是在声明它时在可选类型后面放置感叹号。

注意

如果隐式解包可选,nil并且您尝试访问其包装的值,则会触发运行时错误。结果与在不包含值的普通可选项之后放置感叹号完全相同。

你仍然可以像一个普通的可选项那样对待一个隐式的解包可选,来检查它是否包含一个值:

  1. if assumedString != nil {
  2. print(assumedString)
  3. }
  4. // Prints "An implicitly unwrapped optional string."

你也可以使用一个带有可选绑定的隐式解包可选方法,在一个语句中检查和解包它的值:

  1. if let definiteString = assumedString {
  2. print(definiteString)
  3. }
  4. // Prints "An implicitly unwrapped optional string."

注意

当变量有可能nil在稍后出现时,不要使用隐式解包的可选项如果您需要nil在变量的生命周期中检查,请始终使用正常的可选类型

错误处理

您可以使用错误处理来响应您的程序在执行过程中可能遇到的错误情况。

与可选择性有关,它可以使用值的存在或不存在来传递函数的成功或失败,错误处理允许您确定失败的根本原因,并且,如果有必要,将错误传播到程序的另一部分。

当一个函数遇到一个错误条件时,它会抛出一个错误。然后该函数的调用者可以捕获错误并作出适当的响应。

  1. func canThrowAnError() throws {
  2. // this function may or may not throw an error
  3. }

一个函数指示它可以通过throws在其声明中包含关键字来引发错误当你调用一个可能引发错误的函数时,你try需要在表达式中加上关键字。

Swift自动将错误从当前作用域传出,直到它们被一个catch子句处理

  1. do {
  2. try canThrowAnError()
  3. // no error was thrown
  4. } catch {
  5. // an error was thrown
  6. }

一个do语句创建一个新的包含范围,它允许错误传播到一个或多个catch子句。

以下是错误处理如何用于响应不同错误条件的示例:

  1. func makeASandwich() throws {
  2. // ...
  3. }
  4. do {
  5. try makeASandwich()
  6. eatASandwich()
  7. } catch SandwichError.outOfCleanDishes {
  8. washDishes()
  9. } catch SandwichError.missingIngredients(let ingredients) {
  10. buyGroceries(ingredients)
  11. }

在这个例子中,makeASandwich()如果没有可用的干净的菜肴,或者如果有任何配料丢失,该功能将会报错。因为makeASandwich()可以抛出一个错误,函数调用被包装在一个try表达式中。通过将函数调用包装在一个do语句中,抛出的任何错误都会传播到提供的catch子句中。

如果没有错误,eatASandwich()则调用函数。如果抛出一个错误,并匹配SandwichError.outOfCleanDishes大小写,那么washDishes()函数将被调用。如果抛出一个错误并且匹配SandwichError.missingIngredients大小写,那么该buyGroceries(_:)函数将被调用,并[String]使用catch模式捕获的相关

错误处理中 详细介绍了抛出,捕获和传播错误

断言和先决条件

断言先决条件是在运行时发生的检查。在执行任何进一步的代码之前,使用它们来确保满足基本条件。如果断言或前提条件中的布尔条件评估为true,则代码执行将像往常一样继续。如果条件评估为false,程序的当前状态是无效的; 代码执行结束,你的应用程序被终止。

您使用断言和先决条件来表达您所做的假设以及编码时的期望,这样您就可以将它们包含在代码中。断言有助于您在开发过程中发现错误和不正确的假设,并且先决条件可帮助您检测生产中的问题。

除了在运行时验证您的期望外,断言和先决条件也成为代码中有用的文档形式。与上述错误处理中讨论的错误条件不同,断言和先决条件不用于可恢复或预期的错误。因为失败的断言或先决条件表明一个无效的程序状态,没有办法赶上失败的断言。

使用断言和先决条件不能替代设计代码的方式,以至于不可能出现无效条件。但是,使用它们强制执行有效的数据和状态会导致您的应用程序在发生无效状态时更可预测地终止,并有助于使问题更易于调试。一旦检测到无效状态,立即停止执行也有助于限制由该无效状态造成的损害。

断言和先决条件之间的区别在于它们被检查时:只在调试版本中检查断言,但是在调试版本和生产版本中检查前提条件。在生产构建中,断言内的条件不被评估。这意味着您可以在开发过程中使用尽可能多的断言,而不会影响生产性能。

用断言进行调试

你可以通过调用assert(_:_:file:line:)Swift标准库中函数来编写断言如果条件的结果是,则将此函数传递给计算结果为trueor 的表达式,false并显示要显示的消息false例如:

  1. let age = -3
  2. assert(age >= 0, "A person's age can't be less than zero.")
  3. // This assertion fails because -3 is not >= 0.

在这个例子中,如果age >= 0计算true结果是代码执行继续,也就是说,如果值age是非负的。如果age上面的代码中的值为负数,则age >= 0评估为false,并且断言失败,则终止该应用程序。

你可以省略断言信息 - 例如,当它只是重复作为散文的条件。

  1. assert(age >= 0)

如果代码已经检查了条件,则使用该assertionFailure(_:file:line:)函数来指示断言失败。例如:

  1. if age > 10 {
  2. print("You can ride the roller-coaster or the ferris wheel.")
  3. } else if age > 0 {
  4. print("You can ride the ferris wheel.")
  5. } else {
  6. assertionFailure("A person's age can't be less than zero.")
  7. }

执行先决条件

当条件有可能是错误的时候使用前提条件,但是对于代码继续执行肯定是正确的。例如,使用前提条件来检查下标是否超出范围,或检查函数是否已传递有效值。

你通过调用precondition(_:_:file:line:)函数来编写一个前提条件如果条件的结果是,则将此函数传递给计算结果为trueor 的表达式,false并显示要显示的消息false例如:

  1. // In the implementation of a subscript...
  2. precondition(index > 0, "Index must be greater than zero.")

您也可以调用该preconditionFailure(_:file:line:)函数来指示发生了故障 - 例如,如果采取了开关的默认情况,但所有有效的输入数据都应由交换机的其他情况之一处理。

注意

如果以非检查模式编译(-Ounchecked),则不检查前置条件。编译器假定前置条件总是正确的,并相应地优化了你的代码。但是,fatalError(_:file:line:)无论优化设置如何,该函数都会暂停执行。

您可以fatalError(_:file:line:)在原型开发和早期开发中使用该函数,通过编写fatalError("Unimplemented")存根实现来创建尚未实现的功能的存根。由于致命错误永远不会被优化,与断言或前提条件不同,您可以确保执行始终停止,如果遇到存根实现。

(原文地址) https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309

posted on 2018-01-11 15:21  ZSoYoung  阅读(384)  评论(0)    收藏  举报

导航