Apple Swift 中文教程 高速參考 基本的语法

时间:2023-03-09 03:12:05
Apple Swift 中文教程 高速參考 基本的语法

总的来说。语法有java的味道,也有python的味道,还有swift自己的味道。

有些语法还是挺不伦不类的,不太好理解,即使你有几年的java或python经验,也不见得有些语法你能非常轻松的看明确。

有些语法特性非常好,非常个性,但有些语法个人感觉乱。特性多,注意点多。还不太好理解。

慢慢学习吧。。。

=================================================================

值类型

Int

Double

Bool

String
用双引號""表示

Character
用双引號""表示



Array

Dictionaries



Struct

Enum





引用类型

函数类型(详情请继续往下看)

闭包函数表达式也是引用类型

类类型

=================================================================

类型转换

Int()

Double()

Bool()

String()

=================================================================

比較字符串是否相等直接用==号

=================================================================

nil仅仅能赋值于可选类型

可选类型?

var age:String?

= "21"

可选能够通过if语句来推断是否有值 if age {} else {}

强制解析!

println(age!)

可选绑定

if var ageInt = age.toInt() {}

隐式解析可选类型,不用强制解析。在第一次赋值后。确保永远有值。不用再每次解析是否有值,

一个隐式解析可选类型事实上就是一个普通的可选类型,可是能够被当做非可选类型来使用。并不须要每次都使用解析来获取可选值。

主要被用在 Swift 中类的构造过程中

let age:String! = "21"

println(age)

=================================================================

Swift 的赋值操作并不返回不论什么值,所以if x = y编辑不通过

浮点数求余计算

Swift 也提供恒等===和不恒等!==这两个比較符来推断两个对象是否引用同一个对象实例

闭区间运算符(a...b)定义一个包括从a到b(包括a和b)的全部值的区间

半闭区间(a..b)定义一个从a到b但不包含b的区间

=================================================================

数组

var shoppingList = ["Eggs", "Milk"]

var shoppingList: [String] = ["Eggs", "Milk"]

shoppingList.isEmpty

shoppingList.append("Flour")

shoppingList += "Baking Powder"

shoppingList[4...6] = ["Bananas", "Apples"]

shoppingList.insert("Maple Syrup", atIndex: 0)

shoppingList.removeAtIndex(0)

shoppingList.removeLast()



for item in shoppingList {}

for (index, value) in enumerate(shoppingList) {}





var someInts = [Int]()

someInts = []

var threeDoubles = [Double](count: 3, repeatedValue:0.0)

=================================================================

字典

var airports: Dictionary[String, String] = ["TYO": "Tokyo", "DUB": "Dublin"]

var airports = ["TYO": "Tokyo", "DUB": "Dublin"]

airports.count

airports.updateValue("Dublin Internation", forKey: "DUB")

airports.removeValueForKey("DUB")

airports["APL"] = nil #我们还能够使用下标语法来通过给某个键的相应值赋值为nil来从字典里移除一个键值对



for (airportCode, airportName) in airports {}

for airportCode in airports.keys {}

for airportName in airports.values {}

let airportCodes = [String](airports.keys)

let airportNames = [String](airports.values)





var namesOfIntegers = [Int: String]()

namesOfIntegers = [:]

=================================================================

循环

for index in 1...5 {} #闭区间

for _ in 1..<5 {} #开区间

loop:for var index = 0; index < 3; ++index {}

loop: while condition {

do statements

}

do {

statements

} while condition

=================================================================

分支条件推断

switch value {

#No Implicit Fallthrough

#number

case 1, 2, 3:

do...

case 4...6:

do...

#tuple

case (a, b) where a == b:

do...

case (_, b):

do...

case (a, _):

do...

fallthrough #这个keyword基本用不到

case (1...3, 4...6):

do...

default:

do...

}

=================================================================

函数

函数參数默认是常量。

func halfOpenRangeLength(start: Int, end: Int) -> Int {

    return end - start

}

func sayGoodbye(personName: String) {

    println("Goodbye, \(personName)!")

}

func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {

    return (1, 2, 3)

}

以上3函数,都定义了局部參数名(local parameter name)。它们仅仅能在函数体中使用





func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {

    return s1 + joiner + s2

}

以上1函数。都定义了外部參数名,假设你提供了外部參数名,那么函数在被调用时,必须使用外部參数名





func containsCharacter(#string: String, #characterToFind: Character) -> Bool {

    for character in string {

        if character == characterToFind {

            return true

        }

    }

    return false

}

以上1函数,仅仅写一次參数名,并用井号(#)作为前缀就能够了。

这告诉 Swift 使用这个參数名作为局部和外部參数





func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {

    return s1 + joiner + s2

}

以上1函数。你能够在函数体中为每一个參数定义默认值。当默认值被定义后,调用这个函数时能够忽略这个參数。

将带有默认值的參数放在函数參数列表的最后。

这样能够保证在函数调用时。非默认參数的顺序是一致的。同一时候使得同样的函数在不同情况下调用时显得更为清晰。





func join(s1: String, s2: String, joiner: String = " ") -> String {

    return s1 + joiner + s2

}

以上1函数。为了使定义外部參数名更加简单,当你未给带默认值的參数提供外部參数名时。Swift 会自己主动提供外部名字。

注意: 你能够使用下划线(_)作为默认值參数的外部參数名,这样能够在调用时不用提供外部參数名。可是给带默认值的參数命名总是更加合适的。





func arithmeticMean(numbers: Double...) -> Double {

    var total: Double = 0

    for number in numbers {

        total += number

    }

    return total / Double(numbers.count)

}

以上1函数,定义了可变參数,一个函数至多能有一个可变參数,并且它必须是參数表中最后的一个。





func alignRight(var string: String, count: Int, pad: Character) -> String {

    let amountToPad = count - countElements(string)

    for _ in 1...amountToPad {

        string = pad + string

    }

    return string

}

以上1函数,定义了变量參数。

注意: 对变量參数所进行的改动在函数调用结束后便消失了,而且对于函数体外是不可见的。变量參数只存在于函数调用的生命周期中。





func swapTwoInts(inout a: Int, inout b: Int) {

    let temporaryA = a

    a = b

    b = temporaryA

}

var someInt = 3

var anotherInt = 107

swapTwoInts(&someInt, &anotherInt)

以上1函数。定义了输入输出參数,就好像C语言里的传地址。

swapTwoInts 函数,有两个分别叫做 a 和 b 的输入输出參数。

一个输入输出參数有传入函数的值,这个值被函数改动,然后被传出函数,替换原来的值。

注意: 输入输出參数不能有默认值。并且可变參数不能用 inout 标记。假设你用 inout 标记一个參数。这个參数不能被 var 或者 let 标记。

=================================================================

函数类型

每一个函数都有种特定的函数类型。由函数的參数类型和返回类型组成。例如以下

(Int, Int) -> Int

() -> ()

func addTwoInts(a: Int, b: Int) -> Int {

    return a + b

}

var mathFunction: (Int, Int) -> Int = addTwoInts

let mathFunction = addTwoInts

以上语句,定义一个叫做 mathFunction 的变量,

类型是‘一个有两个 Int 型的參数并返回一个 Int 型的值的函数’,并让这个新变量指向 addTwoInts 函数

就像其它类型一样,当赋值一个函数给常量或变量时,你能够让 Swift 来判断其函数类型:





函数类型作为參数类

func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {

    println("Result: \(mathFunction(a, b))")

}

printMathResult(addTwoInts, 3, 5)

以上语句,你能够用(Int, Int) -> Int这种函数类型作为还有一个函数的參数类型。这样你能够将函数的一部分实现交由给函数的调用者。





函数类型作为返回类型

func stepForward(input: Int) -> Int {

    return input + 1

}

func stepBackward(input: Int) -> Int {

    return input - 1

}

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {

    return backwards ? stepBackward : stepForward

}





以上定义的所有是全局函数

嵌套函数,例如以下

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {

    func stepForward(input: Int) -> Int { return input + 1 }

    func stepBackward(input: Int) -> Int { return input - 1 }

    return backwards ? stepBackward : stepForward

}

默认情况下,嵌套函数是对外界不可见的。可是能够被他们封闭函数(enclosing function)来调用。

一个封闭函数也能够返回它的某一个嵌套函数,使得这个函数能够在其它域中被使用。

=================================================================

闭包(Closures)

闭包能够捕获和存储其所在上下文中随意常量和变量的引用。 

这就是所谓的闭合并包裹着这些常量和变量。俗称闭包。

Swift 会为您管理在捕获过程中涉及到的全部内存操作。





闭包採取例如以下三种形式之中的一个:

全局函数是一个有名字但不会捕获不论什么值的闭包

嵌套函数是一个有名字并能够捕获其封闭函数域内值的闭包

闭包表达式是一个利用轻量级语法所写的能够捕获其上下文中变量或常量值的匿名闭

Swift 的闭包表达式拥有简洁的风格,并鼓舞在常见场景中进行语法优化





reversed = sort(names, { (s1: String, s2: String) -> Bool in

    return s1 > s2

})

以上代码,闭包表达式由{}包裹,函数參数与函数体由keywordin分隔。





reversed = sort(names, { s1, s2 in return s1 > s2 } )

依据上下文判断类型

以上代码,由swift依据sort函数第二个參数已定义好的參数类型与返回值类型。自己主动判断闭包表达式的參数类型和返回值类型





reversed = sort(names, { s1, s2 in s1 > s2 } )

单表达式闭包隐式返回

以上代码,单行表达式闭包能够通过隐藏returnkeyword来隐式返回单行表达式的结果





reversed = sort(names, { $0 > $1 } )

參数名称缩写

以上代码,Swift 自己主动为内联函数提供了參数名称缩写功能。您能够直接通过$0,$1,$2来顺序调用闭包的參数。

inkeyword也相同能够被省略,由于此时闭包表达式全然由闭包函数体构成





reversed = sort(names, >)

运算符函数

以上代码。Swift 的String类型定义了关于大于号 (>) 的字符串实现。其作为一个函数接受两个String类型的參数并返回Bool类型的值。 

因此。您能够简单地传递一个大于号。Swift能够自己主动判断出您想使用大于号的字符串函数实现





func someFunctionThatTakesAClosure(closure: () -> ()) {

    // 函数体部分

}

// 下面是不使用跟随闭包进行函数调用

someFunctionThatTakesAClosure({

    // 闭包主体部分

})

// 下面是使用跟随闭包进行函数调用

someFunctionThatTakesAClosure() {

  // 闭包主体部分

}

// 下面是使用跟随闭包进行函数调用

someFunctionThatTakesAClosure {

  // 闭包主体部分

}

reversed = sort(names) { $0 > $1 }

以上代码,定义了跟随闭包。

当闭包很长以至于不能在一行中进行书写时,跟随闭包变得很实用。

假设函数仅仅须要闭包表达式一个參数。当您使用跟随闭包时,您甚至能够把()省略掉。

注意,跟随闭包表达式仅仅能作为最后一个參数传递给函数。

举例来说。Swift 的Array类型有一个map方法,其获取一个闭包表达式作为其唯一參数。 

let digitNames = [

    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",

    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"

]

let numbers = [16, 58, 510]

let strings = numbers.map {

#闭包函数的參数类型和返回值类型声明

    (var number) -> String in

#函数体从这里開始

    var output = ""

    while number > 0 {

        output = digitNames[number % 10]! + output

        number /= 10

    }

    return output

}

// strings 常量被判断为字符串类型数组,即 String[]

// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]

字典digitNames下标后跟着一个叹号 (!),由于字典下标返回一个可选值 (optional value)。表明即使该 key 不存在也不会查找失败。





func makeIncrementor(forIncrement amount: Int) -> () -> Int {

    var runningTotal = 0

    func incrementor() -> Int {

        runningTotal += amount

        return runningTotal

    }

    return incrementor

}

let incrementByTen = makeIncrementor(forIncrement: 10)

incrementByTen()

// 返回的值为10

let incrementBySeven = makeIncrementor(forIncrement: 7)

incrementBySeven()

// 返回的值为7

incrementByTen()

// 返回的值为20

以上代码,定义了一个捕获值的样例。

=================================================================

枚举

enum CompassPoint {

  case North

  case South

  case East

  case West

}

以上代码,North。South,East和West不是隐式的等于0,1,2和3。

enum Planet {

  case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune

}

以上代码,多个成员值能够出如今同一行上。用逗号隔开

给枚举类型起一个单数名字而不是复数名字。以便于读起来更加easy理解

var directionToHead = CompassPoint.West

directionToHead = .East

以上代码。一旦directionToHead被声明为一个CompassPoint。你能够使用更短的点(.)语法将其设置为还有一个CompassPoint的值





directionToHead = .South

switch directionToHead {

case .North:

    println("Lots of planets have a north")

case .South:

    println("Watch out for penguins")

case .East:

    println("Where the sun rises")

case .West:

    println("Where the skies are blue")

}

// 输出 "Watch out for penguins”

以上代码。以匹配单个枚举值和switch语句,switch语句必须全面





let somePlanet = Planet.Earth

switch somePlanet {

case .Earth:

    println("Mostly harmless")

default:

    println("Not a safe place for humans")

}

// 输出 "Mostly harmless”

以上代码,你能够提供一个默认default分支来涵盖全部未明白被提出的不论什么成员





enum Barcode {

  case UPCA(Int, Int, Int)

  case QRCode(String)

}

以上代码。你能够定义 Swift 的枚举存储不论什么类型的“相关值”,假设须要的话。每一个成员的数据类型能够是各不同样的





enum ASCIIControlCharacter: Character {

    case Tab = "\t"

    case LineFeed = "\n"

    case CarriageReturn = "\r"

}

enum Planet: Int {

    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune

}

以上代码。作为相关值的替代。枚举成员能够被默认值(称为原始值)预先填充。当中这些原始值具有同样的类型。

原始值能够是字符串。字符,或者不论什么整型值或浮点型值。每一个原始值在它的枚举声明中必须是唯一的。

当整型值被用于原始值,假设其它枚举成员没有值时,它们会自己主动递增。

let earthsOrder = Planet.Earth.toRaw()

使用枚举成员的toRaw方法能够訪问该枚举成员的原始值

=================================================================

类和结构体

struct Resolution {

    var width = 0

    var heigth = 0

}

class VideoMode {

    var resolution = Resolution()

    var interlaced = false

    var frameRate = 0.0

    var name: String?

}

let someResolution = Resolution()

let someVideoMode = VideoMode()

能够使用点语法为訪问属性值或为属性赋值

let vga = resolution(width:640, heigth: 480)

全部结构体都有一个自己主动生成的成员逐一构造器。用于初始化新结构体实例中成员的属性。

与结构体不同。类实例没有默认的成员逐一构造器。





用===和!==来推断两个引用是否指向同一个实例

用===和!==来推断两个数组是否共用同样元素





当操作数组内容时。数组(Array)能提供接近C语言的的性能,而且拷贝行为仅仅有在必要时(长度有可能发生变化时)才会发生。

我们通过调用数组的copy方法进行强制显式复制。

假设一个数组被多个变量引用,在当中的一个变量上调用unshare方法,则会拷贝此数组。此时这个变量将会有属于它自己的独立数组拷贝。





假设字典实例中所储存的键(keys)和/或值(values)是值类型(结构体或枚举),当赋值或调用发生时,它们都会被拷贝。

相反。假设键(keys)和/或值(values)是引用类型。被拷贝的将会是引用。而不是被它们引用的类实例或函数。

字典的键和值的拷贝行为与结构体所储存的属性的拷贝行为同样。

=================================================================

属性

存储属性

计算属性

属性观察器





存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值。

计算属性能够用于类、结构体和枚举里,存储属性仅仅能用于类和结构体。

当值类型的实例被声明为常量的时候,它的全部属性也就成了常量。

当把一个引用类型的实例赋给一个常量后,仍然能够改动实例的变量属性。





延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用@lazy来标示一个延迟存储属性。

必须将延迟存储属性声明成变量(使用varkeyword),由于属性的值在实例构造完毕之前可能无法得到。

而常量属性在构造过程完毕之前必需要有初始值。因此无法声明成延迟属性。

计算属性不直接存储值,而是提供一个 getter 来获取值。一个可选的 setter 来间接设置其它属性或变量的值。

假设计算属性的 setter 未定义表示新值的參数名,则能够使用默认名称newValue。

必须使用varkeyword定义计算属性,包含仅仅读计算属性,由于它们的值不是固定的。





能够为除了延迟存储属性之外的其它存储属性加入属性观察器

willSet在设置新的值之前调用,在willSet的实现代码中能够为这个參数指定一个名称。假设不指定则參数仍然可用,这时使用默认名称newValue表示。

didSet在新的值被设置之后马上调用,didSet观察器会将旧的属性值作为參数传入。能够为该參数命名或者使用默认參数名oldValue。

注意:

willSet和didSet观察器在属性初始化过程中不会被调用。它们仅仅会当属性的值在初始化之外的地方被设置时被调用。





使用keywordstatic来定义值类型的类型属性,keywordclass来为类(class)定义类型属性。

举个全面的样例:

class  AlternativeRect {

static var birthday = "2014.01.01"

    var name = "A"

    var age = 18

@lazy var gender = "F"

    var id: String {

get {

return name + "-" + age

}

set {

self.id = newValue

}

willSet {

printf(\(newValue))

}

didSet {

printf(\(oldValue))

}

    }

}

=================================================================

方法

实例方法

类型方法





Swift 默认仅给方法的第一个參数名称一个局部參数名称;默认同一时候给第二个和兴许的參数名称局部參数名称和外部參数名称。

相同。能够用#提供一致的内外參数名。能够用_不提供外部參数名。





结构体和枚举是值类型。普通情况下,值类型的属性不能在它的实例方法中被改动。

你能够选择变异(mutating)这种方法。然后方法就能够从方法内部改变它的属性;

struct Point {

  var x = 0.0, y = 0.0

  mutating func moveByX(deltaX: Double, y deltaY: Double) {

    x += deltaX

    y += deltaY

  }

}





class SomeClass {

  class func someTypeMethod() {

    // type method implementation goes here

  }

}

=================================================================

下标脚本

对于同一个目标能够定义多个下标脚本。通过索引值类型的不同来进行重载。并且索引值的个数能够是多个。

下标脚本同意你通过在实例后面的方括号里传入一个或者多个的索引值来对实例进行訪问和赋值。

定义下标脚本使用subscriptkeyword,显式声明入參(一个或多个)和返回类型。

newValue的类型必须和下标脚本定义的返回类型同样。

struct Matrix {

    let rows: Int, columns: Int

    var grid: Double[]

    init(rows: Int, columns: Int) {

      self.rows = rows

      self.columns = columns

      grid = Array(count: rows * columns, repeatedValue: 0.0)

    }

    func indexIsValidForRow(row: Int, column: Int) -> Bool {

        return row >= 0 && row < rows && column >= 0 && column < columns

    }

    subscript(row: Int, column: Int) -> Double {

        get {

            assert(indexIsValidForRow(row, column: column), "Index out of range")

            return grid[(row * columns) + column]

        }

        set {

            assert(indexIsValidForRow(row, column: column), "Index out of range")

            grid[(row * columns) + column] = newValue

        }

    }

}

=================================================================

继承

在 Swift 中,类能够调用和訪问超类的方法,属性和下标脚本(subscripts),

而且能够重写(override)这些方法。属性和下标脚本来优化或改动它们的行为。

class P {

var numberOfWheels = 0

init(){

numberOfWheels = 1

}

func say(){println("ppppp")}

}

class S : P {

override var numberOfWheels: Int  {

get {

return super.numberOfWheels

}

set {

super.numberOfWheels = min(newValue, 8)

}

    }

init(){

super.init()

numberOfWheels = 2

}

override func say(){println("sssss")}

}

你不能够为继承来的常量存储型属性或继承来的仅仅读计算型属性加入属性观察器。

此外还要注意,你不能够同一时候提供重写的 setter 和重写的属性观察器。

=================================================================

构造过程

类和结构体在实例创建时,必须为全部存储型属性设置合适的初始值。

当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的。不会触发不论什么属性观測器(property observers)。





构造器以keywordinit命名。

构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时,主要通过构造器中的參数名和类型来确定须要调用的构造器。

Swift 会为每一个构造器的參数自己主动生成一个跟内部名字同样的外部名。





可选类型的属性将自己主动初始化为空nil,表示这个属性是有益在初始化时设置为空的。

仅仅要在构造过程结束前常量的值能确定,你能够在构造过程中的随意时间点改动常量属性的值。

对某个类实例来说,它的常量属性仅仅能在定义它的类的构造过程中改动;不能在子类中改动。

Swift 将为全部属性已提供默认值的且自身未定义不论什么构造器的结构体或基类,提供一个默认的构造器。

假设结构体对全部存储型属性提供了默认值且自身没有提供定制的构造器。它们能自己主动获得一个逐一成员构造器。





构造器能够通过调用其他构造器来完毕实例的部分构造过程。这一过程称为构造器代理,它能降低多个构造器间的代码反复。





值类型(结构体和枚举类型)不支持继承。所以构造器代理的过程相对简单,由于它们仅仅能代理给本身提供的其他构造器。

对于值类型。你能够使用self.init在自己定义的构造器中引用其他的属于同样值类型的构造器。而且你仅仅能在构造器内部调用self.init。

注意。假设你为某个值类型定义了一个定制的构造器,你将无法訪问到默认构造器(假设是结构体,则无法訪问逐一对象构造器)。





类里面的全部存储型属性--包含全部继承自父类的属性--都必须在构造过程中设置初始值。





指定构造器和便利构造器。

指定构造器是类中最基本的构造器。

一个指定构造器将初始化类中提供的全部属性,并依据父类链往上调用父类的构造器来实现父类的初始化。

便利构造器是类中比較次要的、辅助型的构造器。

你能够定义便利构造器来调用同一个类中的指定构造器,并为其參数提供默认值。

你也能够定义便利构造器来创建一个特殊用途或特定输入的实例。

构造器链

为了简化指定构造器和便利构造器之间的调用关系,Swift 採用下面三条规则来限制构造器之间的代理调用:

规则 1

指定构造器必须调用其直接父类的的指定构造器。

规则 2

便利构造器必须调用同一类中定义的其他构造器。

规则 3

便利构造器必须终于以调用一个指定构造器结束。

一个更方便记忆的方法是:

指定构造器必须总是向上代理

便利构造器必须总是横向代理

=================================================================

析构过程

通常当你的实例被释放时不须要手动地去清理。可是。当使用自己的资源时。你可能须要进行一些额外的清理。

比如,假设创建了一个自己定义的类来打开一个文件,并写入一些数据。你可能须要在类实例被释放之前关闭该文件。

class P {

deinit {

// 运行析构过程

}

}

=================================================================

自己主动引用计数

引用计数只应用于类的实例。结构体和枚举类型是值类型。不是引用类型,也不是通过引用的方式存储和传递。

仅仅要强引用还在。实例是不同意被销毁的。

在两个类实例互相保持对方的强引用。并让对方不被销毁。这就是所谓的循环强引用。

你能够通过定义类之间的关系为弱引用或者无主引用,以此替代强引用。从而解决循环强引用的问题。

Swift 提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:弱引用(weak reference)和无主引用(unowned reference)。

在实例的生命周期中。假设某些时候引用没有值。那么弱引用能够阻止循环强引用。

假设引用总是有值,则能够使用无主引用。





由于弱引用能够没有值。你必须将每个弱引用声明为可选类型。

弱引用必须被声明为变量。表明其值能在执行时被改动。

弱引用不能被声明为常量。

声明属性或者变量时,在前面加上weakkeyword表明这是一个弱引用。





和弱引用不同的是。无主引用是永远有值的。因此,无主引用总是被定义为非可选类型(non-optional type)。

你能够在声明属性或者变量时,在前面加上keywordunowned表示这是一个无主引用。





Person和Apartment的样例展示了两个属性的值都同意为nil,并会潜在的产生循环强引用。这样的场景最适合用弱引用来解决。

Customer和CreditCard的样例展示了一个属性的值同意为nil,而还有一个属性的值不同意为nil,并会潜在的产生循环强引用。这样的场景最适合通过无主引用来解决。

然而,存在着第三种场景,在这样的场景中,两个属性都必须有值,而且初始化完毕后不能为nil。在这样的场景中,须要一个类使用无主属性,而另外一个类使用隐式解析可选属性。





当闭包和捕获的实例总是互相引用时而且总是同一时候销毁时,将闭包内的捕获定义为无主引用。

相反的,当捕获引用有时可能会是nil时,将闭包内的捕获定义为弱引用。

=================================================================

可先链

假设可选的目标有值,那么调用就会成功;相反。假设选择的目标为空(nil),则这样的调用将返回空(nil)。

多次请求或调用能够被链接在一起形成一个链。假设不论什么一个节点为空(nil)将导致整个链失效。





通过在想调用的属性、方法、或下标脚本的可选值(optional value)(非空)后面放一个问号,能够定义一个可选链。

这一点非常像在可选值后面放一个叹号来强制拆得其封包内的值。

它们的基本的差别在于当可选值为空时可选链即刻失败,然而一般的强制解析将会引发执行时错误。

调用可选链的返回结果与原本的返回结果具有同样的类型。可是原本的返回结果被包装成了一个可选值,

当可选链调用成功时,一个应该返回Int的属性将会返回Int?

class Person {

    var residence: Residence?

}

class Residence {

    var numberOfRooms = 1

}

let john = Person()

let roomCount = john.residence!.numberOfRooms //将导致执行时错误

可选链提供了一种还有一种获得numberOfRooms的方法。利用可选链,使用问号来取代原来!的位置:

if let roomCount = john.residence?.numberOfRooms {

    println("John's residence has \(roomCount) room(s).")

} else {

    println("Unable to retrieve the number of rooms.")

}

// 打印 "Unable to retrieve the number of rooms.

=================================================================

类型转换

类型转换在 Swift 中使用is 和 as操作符实现。

当你不确定转型能够成功时。用类型转换的可选形式(as?)。

你也能够用来检查一个类是否实现了某个协议。

向下转换,向上转换





Swift为不确定类型提供了两种特殊类型别名:

AnyObject能够代表不论什么class类型的实例。

Any能够表示不论什么类型,除了方法类型(function types)。

let someObjects: AnyObject[] = [AnyObject]()

for movie in someObjects as Movie[] {}

var things = [Any]()

=================================================================

嵌套类型

要在一个类型中嵌套还有一个类型,将须要嵌套的类型的定义写在被嵌套类型的区域{}内。并且能够依据须要定义多级嵌套。

Swift同意你定义嵌套类型。能够在枚举类型、类和结构体中定义支持嵌套的类型。

说简单点,就是内部类。

=================================================================

扩展

扩展就是向一个已有的类、结构体或枚举类型加入新功能(functionality)。

这包含在没有权限获取原始源码的情况下扩展类型的能力(即逆向建模)。

Swift 中的扩展能够:

加入计算型属性和计算静态属性

定义实例方法和类型方法

提供新的构造器

定义下标

定义和使用新的嵌套类型

使一个已有类型符合某个协议





extension SomeType {

// 加到SomeType的新功能写到这里

}

extension SomeType: SomeProtocol, AnotherProctocol {

    // 协议实现写到这里

}

extension Double {

    var km: Double { return self * 1_000.0 }

    var m : Double { return self }

    var cm: Double { return self / 100.0 }

    var mm: Double { return self / 1_000.0 }

    var ft: Double { return self / 3.28084 }

}

=================================================================

协议

协议(Protocol)用于定义完毕某项任务或功能所必须的方法和属性,

协议实际上并不提供这些功能或任务的详细实现(Implementation)--而仅仅用来描写叙述这些实现应该是什么样的。

协议能够要求其遵循者提供特定的实例属性,实例方法,类方法,操作符或下标脚本等。

protocol SomeProtocol {

    // 协议内容

}

struct SomeStructure: FirstProtocol, AnotherProtocol {

    // 结构体内容

}

协议能够规定其遵循者提供特定名称与类型的实例属性(instance property)。外也能够指定属性是仅仅读的还是可读写的。

protocol SomeProtocol {

    var mustBeSettable : Int { get set }

    var doesNotNeedToBeSettable: Int { get }

}

常在协议的定义中使用class前缀表示该属性为类成员。在枚举和结构体实现协议时中,须要使用statickeyword作为前缀。

 协议中的方法支持变长參数(variadic parameter),不支持參数默认值(default value)。

 议中类方法的定义与类属性的定义相似。在协议定义的方法前置classkeyword来表示。当在枚举或结构体实现类方法时,须要使用statickeyword来取代。

用类实现协议中的mutating方法时。不用写mutatingkeyword;用结构体,枚举实现协议中的mutating方法时。必须写mutatingkeyword。

协议可以继承一到多个其它协议。语法与类的继承相似。多个协议间用逗号,分隔

 一个协议可由多个协议採用protocol<SomeProtocol。 AnotherProtocol>这种格式进行组合,称为协议合成(protocol composition)。

协议合成并不会生成一个新协议类型,而是将多个协议合成为一个暂时的协议,超出范围后马上失效。

 protocol Named {

    var name: String { get }

}}

protocol Aged {

    var age: Int { get }

}}

struct Person: Named, Aged {

    var name: String

    var age: Int

}}

func wishHappyBirthday(celebrator: protocol<Named, Aged>) {

    println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")

}}

检验协议的一致性

is操作符用来检查实例是否遵循了某个协议。

as?返回一个可选值,当实例遵循协议时。返回该协议类型;否则返回nil

as用以强制向下转型。

@objc用来表示协议是可选的。也能够用来表示暴露给Objective-C的代码。此外。@objc型协议仅仅对类有效。因此仅仅能在类中检查协议的一致性。

协议中使用@optionalkeyword作为前缀来定义可选成员。可选协议在调用时使用可选链。

=================================================================

泛型

func swapTwoValues<T>(inout a: T, inout b: T)

数的泛型版本号使用了占位类型名字(通常此情况下用字母T来表示)来取代实际类型名(如Int、String或Double)。

泛型函数名后面跟着的展位类型名字(T)是用尖括号括起来的(<T>)。

这个尖括号告诉 Swift 那个T是swapTwoValues函数所定义的一个类型。

可支持多个类型參数。命名在尖括号里。用逗号分开。

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {

    // function body goes here

}