Swift The Basics

作者: Harder | 来源:发表于2015-06-17 12:43 被阅读144次

    Swift是一种新出现的开发iOS,OS X 和 watchOS应用程序的编程语言。尽管如此,有 C 和 Objeictive-C 开发经验的你,会从Swift很多部分中发现熟悉的感觉。

    基本类型:Int、Double、Float、Bool、String
    集合类型:Array、Set、Dictionary
    常量:使代码更安全、更清晰
    元组:
    Optional types:表示有值或没值

    Swift是类型安全语言

    变量与常量


    声明

    变量与常量必须先声明,再使用。

    • let 声明常量
    • var 声明变量

    <pre><code>
    let maximumNumberOfLoginAttempts = 10
    var currentLoginAttempt = 0
    </code></pre>

    在一行中声明多个变量或常量,使用逗号分隔
    <pre><code>
    var x = 0.0, y = 0.0, z = 0.0
    </code></pre>

    类型注解

    在变量或常量名后,添加冒号,空格,类型名称
    <pre><code>
    var welcomeMessage: String
    </code></pre>

    在一行中声明多个同类型的变量
    <pre><code>
    var red, green, blue: Double
    </code></pre>

    注:在实际使用中,类型注解很少使用。在定义变量和常量时,如果赋予初始值,Swfit几乎都能推断出类型,细节在“类型安全与类型推断”中。

    命名规范

    几乎支持所有的字符,包括Unicode字符。
    <pre><code>
    let π = 3.14159
    let 你好 = "你好世界"
    let 🐶🐮 = "dogcow"
    </code></pre>

    不能包含空白字符、数学符号、箭头、连字符-、画框线、私有或无效的Unicode code points;不能已数字开始,但是数字可以用在除开始外的其它位置。

    不能声明同名的变量或常量名称,不能存放与声明时不同类型的数据,也不能将常量变为变量-反之亦然。

    注:如果名称与Swift的保留关键字相同,使用`(反单引号)扩住名称。不过,除非别无选择,最好避免使用关键字。

    输出

    可以使用print(_:)函数输出变量或常量的值
    <pre><code>
    var friendlyWelcome = "Bonjour!"
    print(friendlyWelcome)
    // prints "Bonjour!"
    </code></pre>

    print(\_:) 是全局函数,在输出内容后,行尾输出换行符。
    print(\_:appendNewline:)print(\_:),只是有参数控制是否输出换行符

    在输出字符串中使用“\(变量或常量名称)”的形式作为占位符,输出变量或常量的值
    <pre><code>
    print("The current value of friendlyWelcome is (friendlyWelcome)")
    // prints "The current value of friendlyWelcome is Bonjour!"
    </code></pre>

    注释 Comments


    单行注释:
    <pre><code>
    // 注释内容到行尾
    </code></pre>

    多行注释:/* 注释内容 */,多行注释可嵌套使用
    <pre><code>
    /* this is the start of the first multiline comment
    /* this is the second, nested multiline comment */
    this is the end of the first multiline comment */
    </code></pre>

    分号 Semicolons


    Swift不需要在每个语句结尾输入分号,不过你这么做也不会出错。只有一种情况是需要分号的:在一行中输入多条独立的语句
    <pre><code>
    let cat = "🐱"; print(cat)
    // prints "🐱"
    </code></pre>

    整数 Integers


    包括有符号整数:正数、0、负数;无符号整数:正数、0
    Swift的整数:Int8、Int16、Int32、Int64,UInt8、UInt16、UInt32、UInt64

    整数边界 Integer Bounds

    使用每个整数类型,可以获得该类型的最大值(max)与最小值(min)属性:
    <pre><code>
    let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
    let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
    </code></pre>

    浮点数 Floating-Point Numbers


    • Double 表示一个 64-bit 浮点数,15位数字精度
    • Float 表示一个 32-bit 浮点数,6位数字精度

    类型安全与类型推断


    Swift是类型安全的,在编译时将进行类型检查并表示出不匹配的代码。
    类型检查并不意味着需要你在声明时指定每个变量或常量的类型。如果不指定,Swift将使用类型推断(type inferrence)推断出合适的类型

    由于有了类型推断,Swift在声明时需要的类型信息要远少于 C 和 Objective-C。
    在声明变量或常量并赋予初始值时,类型推断尤其有用。

    如下,如果给声明常量meaningOfLife并赋值42,但是没有类型信息,Swift会推断出常量的类型为Int,因为42看起来更像一个整数。
    <pre><code>
    let meaningOfLife = 42
    // meaningOfLife is inferred to be of type Int
    </code></pre>

    同样地,如果指定一个浮点数,Swift推断为Double
    <pre><code>
    let pi = 3.14159
    // pi is inferred to be of type Double
    </code></pre>

    对于浮点数,Swift总是使用Double,如果需要Float,则使用
    <pre><code>
    let pi = Float(3.14159)
    // pi is inferred to be of type Float
    </code></pre>

    如果组合使用整数和浮点数,最终Swift会推断为Double
    <pre><code>
    let anotherPi = 3 + 0.14159
    // anotherPi is also inferred to be of type Double
    </code></pre>

    在这里,3会根据表达式推断为Double

    数字 Numeric Literals


    整数有以下的写法

    • 十进制:十进制数字 (0123456789),没有前缀
    • 二进制:二进制数字(01),前缀为0b
    • 八进制:八进制数字(01234567),前缀为0o
    • 十六进制:十六进制数字(0123456789abcdef),前缀为0x

    <pre><code>以下所有值在十进制中都是17
    let decimalInteger = 17
    let binaryInteger = 0b10001 // 17 in binary notation
    let octalInteger = 0o21 // 17 in octal notation
    let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
    </code></pre>

    浮点数可以使用十进制数(没有前缀)和十六进制拼写,中间必须有个小数点;同时可以有指数形式的写法:十进制用e/E,十六进制用p/P,后面跟指数。

    • 十进制指数,使用基数乘以10exp
      1.25e2 表示 1.25 x 102, or 125.0
      1.25e-2 表示 1.25 x 10-2, or 0.0125.
    • 十六进制指数,使用基数乘以2exp
      0xFp2 means 15 x 22, or 60.0.
      0xFp-2 means 15 x 2-2, or 3.75.

    <pre><code>以下所有值在十进制中都是12.1875
    let decimalDouble = 12.1875
    let exponentDouble = 1.21875e1
    let hexadecimalDouble = 0xC.3p0
    </code></pre>

    数字可以包含格式符号_(下划线)以增强阅读性
    <pre><code>
    let paddedDouble = 000123.456
    let oneMillion = 1_000_000
    let justOverOneMillion = 1_000_000.000_000_1
    </code></pre>
    <pre><code>写成这样也不出错,但是小数点后面得跟数组,最前面(除符号)只能由前导0
    let paddedDouble = -000123.456___e1__0___
    let oneMillion = 0000000000000001_0_0_0_0_0_0______
    let justOverOneMillion = 1_000_000______.0____0__0_000_1______
    </code></pre>

    数值类型转换 Numberic Type Conversion


    写整数时一般使用Int(在XCode7beta上是32位)类型,对非负数也推荐这样用。
    只有在需要的时候,才使用其他整数类型。例如:明确存储空间大小的外部数据、性能、内存或其他的优化

    整数转换 Integer Conversion

    每个整数类型都有一定的数值范围,超出范围的数在编译时将报错
    <pre><code>
    let cannotBeNegative: UInt8 = -1
    // UInt8 cannot store negative numbers, and so this will report an error
    let tooBig: Int8 = Int8.max + 1
    // Int8 cannot store a number larger than its maximum value,
    // and so this will also report an error
    </code></pre>

    要把一个整数转换为另一个类型,需要根据整数数值初始化一个新的目标类型整数。如下:不同类型的整数不能直接运算,要转换为相同类型后才能相加。
    <pre><code>
    let twoThousand: UInt16 = 2_000
    let one: UInt8 = 1
    let twoThousandAndOne = twoThousand + UInt16(one)
    </code></pre>

    SomeType(ofInitialValue)是根据传入值初始化类型数据的默认方法。在幕后,UInt16有个初始化方法接收UInt8类型数据作为初始化参数,所有UInt16才能根据UInt8数据生成新的UInt16数据。

    整数-浮点数转换 Integer and Floating-Point Conversion

    整数与浮点数之间的转换必须明确类型
    <pre><code>
    let three = 3
    let pointOneFourOneFiveNine = 0.14159
    let pi = Double(three) + pointOneFourOneFiveNine
    // pi equals 3.14159, and is inferred to be of type Double
    </code></pre>

    浮点数在转换为整数时,将去掉小数部分,例如:4.75变为整数为4-3.9变为整数位-3

    类型别名 Type Aliases


    使用typealias关键字可以给一个已经存在的类型定义一个别名
    在根据上下文,给类型起一个更贴切的名字,这正是类型别名点用武之地,如:
    <pre><code>
    typealias AudioSample = UInt16
    </code></pre>

    一旦定义了别名,就可以想使用原始类型一样使用别名:
    <pre><code>
    var maxAmplitudeFound = AudioSample.min
    // maxAmplitudeFound is now 0
    </code></pre>

    布尔类型 Booleans


    Swift的布尔类型为Bool,布尔值是逻辑值,只有 true、false 两个常量值
    <pre><code>
    let orangesAreOrange = true
    let turnipsAreDelicious = false
    </code></pre>

    Swift的Type Inference机制会推断出他们是Bool类型的数据

    布尔值主要用在条件语句中,比如if语句:
    <pre><code>
    if turnipsAreDelicious {
    print("Mmm, tasty turnips!")
    } else {
    print("Eww, turnips are horrible.")
    }
    // prints "Eww, turnips are horrible."
    </code></pre>

    Swift的类型安全机制会阻止使用非布尔值替代Bool,下例在编译时将会报错:
    <pre><code>
    let i = 1
    if i {
    // this example will not compile, and will report an error
    }
    </code></pre>

    不过,这样使用就是正确的了
    <pre><code>
    let i = 1
    if i == 1 {
    // this example will compile successfully
    }
    </code></pre>
    i == 1的结果是Bool类型

    元组 Tuples


    元组是一个复合值,由多个值组成,每个组成元组的值可以是任意类型,不必都是同一个类型的值
    例如(404, "Not Found"),这个元组描述一个 HTTP 状态值,状态码404表示资源未找到
    <pre><code>
    let http404Error = (404, "Not Found")
    // http404Error is of type (Int, String), and equals (404, "Not Found")
    </code></pre>

    元组(404, "Not Found")包含一个Int和一个String,类型可以看成是(Int, String)

    可以使用任意一组类型的排列创建元组,例如:(Int, Int, Int),或者(String, Bool),或者其他你想要的类型排列方式

    使用如下方式使用元组内数据
    <pre><code>
    let (statusCode, statusMessage) = http404Error
    print("The status code is (statusCode)")
    // prints "The status code is 404"
    print("The status message is (statusMessage)")
    // prints "The status message is Not Found"
    </code></pre>

    如果只关注元组内的一部分数据,可以使用下划线(_)忽略不想要的部分
    <pre><code>
    let (justTheStatusCode, _) = http404Error
    print("The status code is (justTheStatusCode)")
    // prints "The status code is 404"
    </code></pre>

    或者,可以使用索引(从0开始)的方式访问元组内容
    <pre><code>
    print("The status code is (http404Error.0)")
    // prints "The status code is 404"
    print("The status message is (http404Error.1)")
    // prints "The status message is Not Found"
    </code></pre>

    也可以给元组内的值起个名字,这样就可以通过名字来访问了(给某个值起名,其他不起名也可以,我在playground中测了一下)
    <pre><code>
    let http200Status = (statusCode: 200, description: "OK")
    <br />
    print("The status code is (http200Status.statusCode)")
    // prints "The status code is 200"
    print("The status message is (http200Status.description)")
    // prints "The status message is OK"
    </code></pre>

    Optionals (这个怎么翻译好?)


    声明一个变量、返回结果、属性等可能处在有值、没有值两种状态:

    • 没有值,在objc里就是nil
    • 有值,就是他的内容

    在 C 和 Objective-C中,不存在这个概念。比较接近的是在Objective-C中,一个方法可能返回nil,也可能返回一个对象。nil就意味着没有有效值。但是在Objective-C中,基础类型、结构、枚举作为方法返回值时就不能返回nil,只能返回特定的值(如NSNotFound)表示没有返回有效值。

    下例就展示Optional在处理无效值时的使用方法
    <pre><code>
    et possibleNumber = "123"
    let convertedNumber = Int(possibleNumber)
    let unconvertNumber = Int("Hello World!")
    // convertedNumber is inferred to be of type "Int?", or "optional Int", value is 123
    // unconvertNumber is inferred to be of type "Int?", value is nil
    </code></pre>

    nil

    可以给Optional变量赋值为nil,表示无值
    <pre><code>
    var serverResponseCode: Int? = 404
    // serverResponseCode contains an actual Int value of 404
    serverResponseCode = nil
    // serverResponseCode now contains no value
    </code></pre>

    nil 不能用在非Optional的变量和常量上,如果想使用无值的变量或常量,那就把他声明为Optional

    如果定义了一个Optional变量但是没有初始化,那么变量自动为nil
    <pre><code>
    var surveyAnswer: String?
    // surveyAnswer is automatically set to nil
    </code></pre>

    注:Swift的nil 与 Objective-C的nil是不同的。在Objective-C中,nil表示一个指向不存在对象的指针;在Swift中,nil不是指针,他表示某一类型的值没有出现(没赋值)。任意Optional类型都可以赋值nil,而不仅仅是对象类型。

    If Statements and Forced Unwrapping

    使用if语句与nil比较能判断一个Optional 是否有值。可以使用等于操作符== 或 不等于操作符!=执行判断

    如果Optional没有值,那么就与nil不相等
    <pre><code>
    if convertedNumber != nil {
    print("convertedNumber contains some integer value.")
    }
    // prints "convertedNumber contains some integer value."
    </code></pre>

    如果确定Optional有值,就可以在名称后面紧跟叹号(!)来访问他的值。这个就叫forced unwrapping(强制解包?)
    <pre><code>
    if convertedNumber != nil {
    print("convertedNumber has an integer value of (convertedNumber!).")
    }
    // prints "convertedNumber has an integer value of 123."
    </code></pre>

    注:如果对无值的Optional使用!,将会引发运行时错误。所以在使用!前一定要确保Optional 含有非nil

    Optional Binding

    使用Optional Binding检查Optional是否有值,如果有,可以创建一个临时的变量或常量来使用该值。可以用于ifwhile语句,检查Optional是否有值,并提取该值到一个变量或常量中

    if语句中使用Optional Binding,如下:
    <pre><code>
    if let constantName = someOptional {
    statements
    }
    </code></pre>

    在Optional一节中possibleNumber的例子,可以使用Optional Binding的方式重写,而不使用Forced Unwrapping
    <pre><code>
    if let actualNumber = Int(possibleNumber) {
    print("'(possibleNumber)' has an integer value of (actualNumber)")
    } else {
    print("'(possibleNumber)' could not be converted to an integer")
    }
    // prints "'123' has an integer value of 123"
    </code></pre>

    上例可以解读为:如果Int(possibleNumber)返回的Optional Int有值,就将值赋值给常量actualNumber

    如果转换成功,常量actualNumberif语句的第一个分支中变为可用。由于actualNumber已经使用Optional的值初始化,所以这里就不需再使用!后缀来访问其值。

    Optional Binding时可以使用常量或变量。如果想改变actualNumber的值,则使用if var actualNumber =代替上例中的if let actualNumber =

    如果有多个Optional需要Optional Binding,可以把它们都写在一起(一行或多行),用逗号分隔。
    <pre><code>
    if let [constantName] = [someOptional], [anotherConstantName] = [someOtherOptional] {
    [statements]
    }
    </code></pre>

    Implicitly Unwrapped Optionals

    如上所述,Optional表示变量或常量可以为“无值”。Optional可以使用if语句检查是否有值;如果有值,也可以使用Optional Binding有条件的展开来访问其值

    有时,从程序结构上来看Optional总是有值。这种情况下,因为可以安全地假定Optional一直有值,那么取消检查与解包Optional的值,对于每次访问来说是有益处的。

    这种Optional就可以定义为implicitly unwrapping optionals,将问号(String?)替换为叹号(String!),之前的Optional就成为了implicitly unwrapping optionals

    implicitly unwrapping optionals在这种情况下有用:在optional第一次定义时就能立即明确其有值,并可确信此之后一直有值。在Swift中,implicitly unwrapping optionals主要用于类初始化的时候。

    implicitly unwrapping optionals其实就是一个普通的Optional,但是可以当作非Optional值来使用,并且不用在每次访问都时候都对其解包。接下来的例子将说明,在以explicit String的方式访问optional String 与 implicitly unwrapping optionals String时中的值时,在行为上有什么不同:
    <pre><code>
    let possibleString: String? = "An optional string."
    let forcedString: String = possibleString! // requires an exclamation mark
    <br />
    let assumedString: String! = "An implicitly unwrapped optional string."
    let implicitString: String = assumedString // no need for an exclamation mark
    </code></pre>

    可以认为implicitly unwrapping optionals是被许可在使用时自动解包的Optional。与每次使用Optional时将叹号!放在名称后面不同的是:implicitly unwrapping optionals要求将叹号!放在声明时的类型后面

    注:如果访问无值的implicitly unwrapping optionals,将会引发运行时错误(runtime error),这与访问无值Optional时将叹号!放在名称后面一样,都会引发的运行时错误。

    implicitly unwrapping optionals可以与普通的Optional一样,在if语句中检查是否为有值:
    <pre><code>
    if assumedString != nil {
    print(assumedString)
    }
    // prints "An implicitly unwrapped optional string."
    </code></pre>

    implicitly unwrapping optionals也可以用于Optional Binding,检查并解包其值:
    <pre><code>
    if let definiteString = assumedString {
    print(definiteString)
    }
    // prints "An implicitly unwrapped optional string."
    </code></pre>

    注:如果变量在以后某刻可能为nil,就不要使用implicitly unwrapping optionals,而是使用普通的Optional类型,用于检查其是否有值。

    错误处理 Error Handling


    使用错误处理(Error Handling)应对在程序运行时遇到的突发的错误情况

    相比于使用Optional可以在函数成功或失败时返回有值或无值,错误处理让你有机会判断引发错误的原因,如果有必要,还可以将错误继续传递到程序的其他部分去处理

    当函数发生错误,就会抛出一个error,函数调用中可以捕获这个错误并进行适当处理
    <pre><code>
    func canThrowAnError() throws {
    // this function may or may not throw an error
    }
    </code></pre>

    声明函数时,在括号后紧跟throws关键字。当调用一个可能抛出错误的函数时,必须在函数前使用try关键字。

    Swift会自动将error从其当前的作用域向外传递,直到遇到有catch处理这个错误
    <pre><code>
    do {
    try canThrowAnError()
    // no error was thrown
    } catch {
    // an error was thrown
    }
    </code></pre>

    do语句创建了一个作用域,可以使错误传递给一个或多个catch处理

    下例将展示错误处理怎样响应不同情况的错误
    <pre><code>
    func makeASandwich() throws {
    // ...
    }
    <br />
    do {
    try makeASandwich()
    eatASandwich()
    } catch Error.OutOfCleanDishes {
    washDishes()
    } catch Error.MissingIngredients(let ingredients) {
    buyGroceries(ingredients)
    }
    </code></pre>

    本例中,makeASandwich()函数会在没有干净盘子或没有食材不全时抛出错误。因为makeASandwich()声明为throws,所以要使用try来调用。将调研放倒do语句里,有错误产生时将会被传递到对应的catch语句中处理

    如果没有错误发生,eatASandwich()函数将被调用;如果抛出了Error.OutOfCleanDishes错误,washDishes()函数将被调用;如果抛出了Error.MissingIngredients错误,buyGroceries(_:)函数将被调用,同时在catch中会得到缺失的食材数组[String]

    以后会有单章来更详细地介绍throwing, catching, and propagating errors

    断言 Assertions


    有时,当特定的条件得不到满足时,程序将无法继续执行。碰到这种情况,就可以引发一个assertion来结束程序执行,使debug有机会去判断产生assertion原因(无效值或无值)。

    Debugging with Assertions

    Assertion就是在运行时检查其逻辑条件评估后是否为true。从字面来讲,断言断定条件为true。可以使用Assertion确保在运行其后的代码时,必要的条件已经得到满足。

    如果在Debug时,代码引发了assertion,比如你正在使用XCode生成运行app,你就可以准确地找到无效状态的位置,并查询发生assertion时程序的状态。Assertion还允许你提供恰当的信息用以描述引发assertion的原因

    使用全局函数assert(_:_:)来描述一个断言。它有两个参数,其一是一个表达式用以评估其结果为truefalse,另一个是断言的描述信息,当表达式结果为false时将会显示。
    <pre><code>
    let age = -3
    assert(age >= 0, "A person's age cannot be less than zero")
    // this causes the assertion to trigger, because age is not >= 0
    </code></pre>

    本例中,如果age >= 0true,即:age为非负数,就继续执行;如果age是负数,就会引发断言,结束程序执行。

    如果不想要断言描述信息,可以使用如下形式调用
    <pre><code>
    assert(age >= 0)
    </code></pre>

    When to Use Assertions

    断言用于当条件有可能不成立,但是必须成立时程序才能继续执行的地方。使用断言的合适的情景:

    • 传给自定义下标函数的下标值是否在正确范围内
    • 传给函数一个无效值,导致不能完成其功能
    • 当前Optional是nil,但是随后的代码需要其非nil是才能执行成功

    注:断言会导致程序终止,并且设计代码时不太可能出现的无效条件最好不要使用断言。尽管如此,在程序发布前的开发阶段,如果无效条件可能出现,断言也是发现无效条件的有效方法

    参考:The Swift Programming Language

    相关文章

      网友评论

        本文标题:Swift The Basics

        本文链接:https://www.haomeiwen.com/subject/smfsqttx.html