/* This is also a comment but is written over multiple lines. 块注释 */
注释嵌套
1 2 3
/* 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. */
整型
整形有8,16,32,64位的
支持有符号,无符号
整型范围
1 2
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
Int,平台无关的有符号整型
32位平台上,长度同Int32
64位平台上,长度同Int64
UInt,平台无关的无符号整型
32位平台上,长度同UInt32
64位平台上,长度同UInt64
浮点型
Float,单精度浮点型,32位
Double,双精度浮点型,64位
类型安全与类型推断
略
数值字面值
整型
1 2 3 4
let decimalInteger = 17// 十进制 let binaryInteger = 0b10001// 17 in binary notation 二进制 let octalInteger = 0o21// 17 in octal notation 八进制 let hexadecimalInteger = 0x11// 17 in hexadecimal notation 十六进制
浮点型
略
数值类型转换
整型转换
1 2 3
let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one)
浮点型转换
int to float
1 2 3 4
let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine // pi equals 3.14159, and is inferred to be of type Double
float to int
1 2 3
let integerPi = Int(pi) // integerPi equals 3, and is inferred to be of type Int // 等于3,被截断
类型别名
1 2
// 定义别名 typealiasAudioSample = UInt16
1 2 3
// 使用别名 var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound is now 0
元组
定义元组
1 2
let http404Error = (404, "Not Found") // http404Error is of type (Int, String), and equals (404, "Not Found")
访问元组值
1 2 3 4 5
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"
使用_忽略部分元组值
1 2 3
let (justTheStatusCode, _) = http404Error print("The status code is \(justTheStatusCode)") // Prints "The status code is 404"
用索引访问元组值
1 2 3 4
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"
定义带名字的元组值
1
let http200Status = (statusCode: 200, description: "OK")
使用带名字的元组值
1 2 3 4
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"
可选类型
1 2 3 4
let possibleNumber = "123" let convertedNumber = Int(possibleNumber) // convertedNumber is inferred to be of type "Int?", or "optional Int" // 字符串转int的时候有可能失败,所以返回的是可选类型
nil
略
if声明和强制解包
if判断后,用!来强制解包
1 2 3 4
if convertedNumber != nil { print("convertedNumber has an integer value of \(convertedNumber!).") // 使用!强制解包 } // Prints "convertedNumber has an integer value of 123."
可选绑定
如果可选类型不为nil,就会提取值到actualNumber上,
否则走else分支
1 2 3 4 5 6
iflet 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"
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
1
assert(age >= 0)
什么时候使用断言
可能超出自定义下标范围的时候
可能有无效的函数参数
下文需要用到可选类型的值,但是可选类型可能为nil的时候
基本运算符
略(加减乘除等)
术语
No.
Name
Demo
1
一元运算符
-a,!b,c!
2
二元运算符
a + b
3
三元运算符
a ? b : c
赋值运算符
1 2 3 4
let b = 10 var a = 5 a = b // a is now equal to 10
1 2
let (x, y) = (1, 2) // x is equal to 1, and y is equal to 2
算术运算符
略(加减乘除等)
取余运算符
略(%)
一元减运算符
略(-)
一元加运算符
略(+)
混合运算符
略(+=等)
比较运算符
==
!=
>
<
>=
<=
元组的比较
如果元组的类型相同,而且各个元素都是可以比较的话,就能用比较运算符。
1 2 3
(1, "zebra") < (2, "apple") // true because 1 is less than 2 (3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird" (4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"
三元条件运算符
略(a ? b : c)
nil合并运算符(Nil-Coalescing Operator)(* 不确定是不是这个名字)
功能:可选类型为nil的时候赋予默认值。
1 2 3 4 5 6
let defaultColorName = "red" var userDefinedColorName: String? // defaults to nil,默认为nil var colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName is nil, so colorNameToUse is set to the default of "red" // 可选类型为nil,所以赋值为"red"
1 2 3 4
userDefinedColorName = "green" colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName is not nil, so colorNameToUse is set to "green" // 可选类型不为nil,所以赋值为"green"
区间运算符(Range Operators)
有两种:
闭区间运算符,a...b,包前包后
半开区间运算符,a..<b,包前不包后
1 2 3 4 5 6 7 8
for index in1...5 { print("\(index) times 5 is \(index * 5)") } // 1 times 5 is 5 // 2 times 5 is 10 // 3 times 5 is 15 // 4 times 5 is 20 // 5 times 5 is 25
1 2 3 4 5 6 7 8 9
let names = ["Anna", "Alex", "Brian", "Jack"] letcount = names.count for i in0..<count { print("Person \(i + 1) is called \(names[i])") } // Person 1 is called Anna // Person 2 is called Alex // Person 3 is called Brian // Person 4 is called Jack
逻辑运算符
略(与或非)
字符串与字符
字符串字面值
1
let someString = "Some string literal value"// 双引号范围内的就是字符串字面值
初始化一个空字符串
有两种方法
1 2 3
var emptyString = ""// empty string literal var anotherEmptyString = String() // initializer syntax // these two strings are both empty, and are equivalent to each other
判断是否为空
1 2 3 4
if emptyString.isEmpty { print("Nothing to see here") } // Prints "Nothing to see here"
字符串可变性
变量可变,常量不可变。
1 2 3 4 5 6 7 8 9
var variableString = "Horse" variableString += " and carriage" // variableString is now "Horse and carriage" // 字符串改变 let constantString = "Highlander" constantString += " and another Highlander" // this reports a compile-time error - a constant string cannot be modified // ❎,编译错误
字符串是值类型
也就是说,赋值或者传递参数的时候会拷贝一个副本。
操作字符
遍历字符串中的字符
1 2 3 4 5 6 7 8
for character in"Dog!🐶".characters { print(character) } // D // o // g // ! // 🐶
字符变量定义
1
let exclamationMark: Character = "!"
字符数组转字符串
1 2 3 4
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) print(catString) // Prints "Cat!🐱"
连接字符串和字符
1 2 3 4
let string1 = "hello" let string2 = " there" var welcome = string1 + string2 // 用+连接字符串 // welcome now equals "hello there"
1 2 3
var instruction = "look over" instruction += string2 // 用+=连接字符串 // instruction now equals "look over there"
1 2 3
let exclamationMark: Character = "!" welcome.append(exclamationMark) // 添加字符到字符串上 // welcome now equals "hello there!"
字符串插入
1 2 3
let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"// 在字符串中插入变量 // message is "3 times 2.5 is 7.5"
字符串中的特殊符号
用\插入特殊符号
用\u插入unicode
1 2 3 4 5
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"// // "Imagination is more important than knowledge" - Einstein let dollarSign = "\u{24}"// $, Unicode scalar U+0024 let blackHeart = "\u{2665}"// ♥, Unicode scalar U+2665 let sparklingHeart = "\u{1F496}"// 💖, Unicode scalar U+1F496
扩展字形组(* 不确定不是不是这个名字)
(警告: 这里也不是特别理解,需要自己去看下原文)
一个扩展自行组可能由一个或者多个Unicode标量组成。
比如:é有两种表示方法
U+00E9
U+0065 U+0301
1 2 3
let eAcute: Character = "\u{E9}"// é let combinedEAcute: Character = "\u{65}\u{301}"// e和 ́ // eAcute is é, combinedEAcute is é
两者都是一个swift字符。前者一个Unicode标量,后者两个。
1 2 3
let precomposed: Character = "\u{D55C}"// 한 let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"// ᄒ, ᅡ, ᆫ // precomposed is 한, decomposed is 한
1 2
let enclosedEAcute: Character = "\u{E9}\u{20DD}" // enclosedEAcute is é⃝
1 2
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}" // regionalIndicatorForUS is 🇺🇸
计算字符数
1 2 3
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" print("unusualMenagerie has \(unusualMenagerie.characters.count) characters") // Prints "unusualMenagerie has 40 characters"
由于前文的原因,删减字符串中的字符不一定会改变字符数
1 2 3 4 5 6 7 8 9
var word = "cafe" print("the number of characters in \(word) is \(word.characters.count)") // Prints "the number of characters in cafe is 4" word += "\u{301}"// COMBINING ACUTE ACCENT, U+0301 print("the number of characters in \(word) is \(word.characters.count)") // Prints "the number of characters in café is 4" // e加个字符 ́变成了é,字符总数没变
let greeting = "Guten Tag!" greeting[greeting.startIndex] // G greeting[greeting.index(before: greeting.endIndex)] // ! greeting[greeting.index(after: greeting.startIndex)] // u let index = greeting.index(greeting.startIndex, offsetBy: 7) greeting[index] // a
访问所有字符串的字符索引
1 2 3 4
for index in greeting.characters.indices { print("\(greeting[index]) ", terminator: "") } // Prints "G u t e n T a g ! "
插入与删除
1 2 3 4 5 6
var welcome = "hello" welcome.insert("!", at: welcome.endIndex) // 插入单个字符 // welcome now equals "hello!" welcome.insert(contentsOf:" there".characters, at: welcome.index(before: welcome.endIndex)) // 插入字符串 // welcome now equals "hello there!"
1 2 3 4 5 6
welcome.remove(at: welcome.index(before: welcome.endIndex)) // 删除单个字符 // welcome now equals "hello there" let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex welcome.removeSubrange(range) // 删除区间 // welcome now equals "hello"
比较字符串
字符与字符串的相等性
==判断相等
!=判断不相等
1 2 3 4 5 6
let quotation = "We're a lot alike, you and I." let sameQuotation = "We're a lot alike, you and I." if quotation == sameQuotation { print("These two strings are considered equal") } // Prints "These two strings are considered equal"
由于上文的扩展字形组的原因,由不同Unicode标量组成的字符串也可能相等。
比如:
1 2 3 4 5 6 7 8 9 10
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE let eAcuteQuestion = "Voulez-vous un caf\u{E9}?" // "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?" if eAcuteQuestion == combinedEAcuteQuestion { print("These two strings are considered equal") } // Prints "These two strings are considered equal"
相反,两个长得一样的字符也可能不相等。
比如:
拉丁字符A,与西里尔字符А
1 2 3 4 5 6 7 8
let latinCapitalLetterA: Character = "\u{41}" let cyrillicCapitalLetterA: Character = "\u{0410}" if latinCapitalLetterA != cyrillicCapitalLetterA { print("These two characters are not equivalent.") } // Prints "These two characters are not equivalent."
前缀与后缀相等性
1 2 3 4 5 6 7 8 9 10 11 12 13
let romeoAndJuliet = [ "Act 1 Scene 1: Verona, A public place", "Act 1 Scene 2: Capulet's mansion", "Act 1 Scene 3: A room in Capulet's mansion", "Act 1 Scene 4: A street outside Capulet's mansion", "Act 1 Scene 5: The Great Hall in Capulet's mansion", "Act 2 Scene 1: Outside Capulet's mansion", "Act 2 Scene 2: Capulet's orchard", "Act 2 Scene 3: Outside Friar Lawrence's cell", "Act 2 Scene 4: A street in Verona", "Act 2 Scene 5: Capulet's mansion", "Act 2 Scene 6: Friar Lawrence's cell" ]
前缀
1 2 3 4 5 6 7 8
var act1SceneCount = 0 for scene in romeoAndJuliet { if scene.hasPrefix("Act 1 ") { act1SceneCount += 1 } } print("There are \(act1SceneCount) scenes in Act 1") // Prints "There are 5 scenes in Act 1"
后缀
1 2 3 4 5 6 7 8 9 10 11
var mansionCount = 0 var cellCount = 0 for scene in romeoAndJuliet { if scene.hasSuffix("Capulet's mansion") { mansionCount += 1 } elseif scene.hasSuffix("Friar Lawrence's cell") { cellCount += 1 } } print("\(mansionCount) mansion scenes; \(cellCount) cell scenes") // Prints "6 mansion scenes; 2 cell scenes"
for codeUnit in dogString.utf16 { print("\(codeUnit) ", terminator: "") } print("") // Prints "68 111 103 8252 55357 56374 "
UTF-32结构
1 2 3 4 5
for scalar in dogString.unicodeScalars { print("\(scalar.value) ", terminator: "") } print("") // Prints "68 111 103 8252 128054 "
1 2 3 4 5 6 7 8
for scalar in dogString.unicodeScalars { print("\(scalar) ") } // D // o // g // ‼ // 🐶
集合类型
3种主要的集合类型
array,数组
set,集
dictionary,字典
集合的可变性
集合是变量的话,长度和内容可变
集合是常量的话,长度和内容不可变
数组
元素有序,可重复
数组简写语法
1 2
Array<Element> // 原始写法 [Element] // 简写(推荐)
创建一个空数组
1 2 3
var someInts = [Int]() print("someInts is of type [Int] with \(someInts.count) items.") // Prints "someInts is of type [Int] with 0 items."
1 2 3 4
someInts.append(3) // someInts now contains 1 value of type Int someInts = [] // 类型已知的时候,可以这样写 // someInts is now an empty array, but is still of type [Int]
创建一个有默认值的数组
1 2
var threeDoubles = Array(repeating: 0.0, count: 3) // 含有3个元素,每个默认值为0.0 // threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
合并数组
1 2 3 4 5
var anotherThreeDoubles = Array(repeating: 2.5, count: 3) // anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5] var sixDoubles = threeDoubles + anotherThreeDoubles // 直接用+ // sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
创建数组字面值
1 2
var shoppingList: [String] = ["Eggs", "Milk"] // shoppingList has been initialized with two initial items
1
var shoppingList = ["Eggs", "Milk"] // 简写,使用类型推断为string数组
访问与修改数组
1 2
print("The shopping list contains \(shoppingList.count) items.") // count元素个数 // Prints "The shopping list contains 2 items."
1 2 3 4 5 6 7
// isEmpty判断是否为空 if shoppingList.isEmpty { print("The shopping list is empty.") } else { print("The shopping list is not empty.") } // Prints "The shopping list is not empty."
1 2
shoppingList.append("Flour") // append添加新元素 // shoppingList now contains 3 items, and someone is making pancakes
shoppingList.insert("Maple Syrup", at: 0) // 插入元素 // shoppingList now contains 7 items // "Maple Syrup" is now the first item in the list
1 2 3 4
let mapleSyrup = shoppingList.remove(at: 0) // 删除元素 // the item that was at index 0 has just been removed // shoppingList now contains 6 items, and no Maple Syrup // the mapleSyrup constant is now equal to the removed "Maple Syrup" string
1 2 3 4
let apples = shoppingList.removeLast() // 删除最后一个元素 // the last item in the array has just been removed // shoppingList now contains 5 items, and no apples // the apples constant is now equal to the removed "Apples" string
1 2 3 4 5 6 7 8 9
// 遍历元素 for item in shoppingList { print(item) } // Six eggs // Milk // Flour // Baking Powder // Bananas
集
元素无序,而且唯一
集类型的哈希值
集中的元素必须是可哈希的。
哈希值是一个Int值,用来判断元素的相等性
swift的基本元素都是可哈希的,也就是说可以放入集。
集的语法
1
Set<Element>
创建一个空的集
1 2 3
var letters = Set<Character>() print("letters is of type Set<Character> with \(letters.count) items.") // Prints "letters is of type Set<Character> with 0 items."
1 2 3 4
letters.insert("a") // letters now contains 1 value of type Character letters = [] // 类型已知的时候可以这样清空 // letters is now an empty set, but is still of type Set<Character>
创建一个有数组字面值的集
1 2
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"] // favoriteGenres has been initialized with three initial items
1
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"] // 类型可以推断的时候可以简写
访问与修改集
1 2
print("I have \(favoriteGenres.count) favorite music genres.") // 元素个数 // Prints "I have 3 favorite music genres."
1 2 3 4 5 6 7
// 是否为空 if favoriteGenres.isEmpty { print("As far as music goes, I'm not picky.") } else { print("I have particular music preferences.") } // Prints "I have particular music preferences."
1 2
favoriteGenres.insert("Jazz") // 插入 // favoriteGenres now contains 4 items
1 2 3 4 5 6 7 8
// 删除 // 删除的时候会返回删除的值的可选值,如果为nil就是没有 iflet removedGenre = favoriteGenres.remove("Rock") { print("\(removedGenre)? I'm over it.") } else { print("I never much cared for that.") } // Prints "Rock? I'm over it."
1 2 3 4 5 6 7
// 检查是否包含 if favoriteGenres.contains("Funk") { print("I get up on the good foot.") } else { print("It's too funky in here.") } // Prints "It's too funky in here."
1 2 3 4 5 6 7
// 迭代 for genre in favoriteGenres { print("\(genre)") } // Jazz // Hip hop // Classical
1 2 3 4 5 6 7 8
// 排序 // 集本身是无序的,想要排序需要调用sorted方法 for genre in favoriteGenres.sorted() { print("\(genre)") } // Classical // Hip hop // Jazz
集运算
基本的集运算
intersection(_:)求交集,a,b中都有的元素
symmetricDifference(_:),(不知道叫什么),a,b含有的不同元素
union(_:)求并集,a,b中所有的元素
subtracting(_:),(不知道叫什么),在a中不在b中的元素
1 2 3 4 5 6 7 8 9 10 11 12
let oddDigits: Set = [1, 3, 5, 7, 9] let evenDigits: Set = [0, 2, 4, 6, 8] let singleDigitPrimeNumbers: Set = [2, 3, 5, 7] oddDigits.union(evenDigits).sorted() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] oddDigits.intersection(evenDigits).sorted() // [] oddDigits.subtracting(singleDigitPrimeNumbers).sorted() // [1, 9] oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted() // [1, 2, 9]
let houseAnimals: Set = ["🐶", "🐱"] let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"] let cityAnimals: Set = ["🐦", "🐭"] houseAnimals.isSubset(of: farmAnimals) // true farmAnimals.isSuperset(of: houseAnimals) // true farmAnimals.isDisjoint(with: cityAnimals) // true
字典
字典的简写
1
Dictionary<Key, Value> // 全写
1
[Key: Value] // 类型已知的时候可以简写
创建空字典
1 2
var namesOfIntegers = [Int: String]() // namesOfIntegers is an empty [Int: String] dictionary
1 2 3 4
namesOfIntegers[16] = "sixteen"// 插入 // namesOfIntegers now contains 1 key-value pair namesOfIntegers = [:] // 清空 // namesOfIntegers is once again an empty dictionary of type [Int: String]
创建带字面值的字典
1
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
1
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] // 简写
访问与修改字典
1 2
print("The airports dictionary contains \(airports.count) items.") // 元素个数 // Prints "The airports dictionary contains 2 items."
1 2 3 4 5 6 7
// 是否为空 if airports.isEmpty { print("The airports dictionary is empty.") } else { print("The airports dictionary is not empty.") } // Prints "The airports dictionary is not empty."
1 2
airports["LHR"] = "London"// 插入 // the airports dictionary now contains 3 items
1 2
airports["LHR"] = "London Heathrow"// 如果已经有key的话,就变成了修改了 // the value for "LHR" has been changed to "London Heathrow"
1 2 3 4 5 6
// updateValue,同上面两个一样也是插入或者更新值。 // 不同的是,方法返回一个可选值,如果是更新,会返回原来的值,否则返回nil,这样可以用来确认是否是更新 iflet oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") { print("The old value for DUB was \(oldValue).") } // Prints "The old value for DUB was Dublin."
1 2 3 4 5 6 7
// 同理,用下标访问字典也是一样,返回元素可选值 iflet airportName = airports["DUB"] { print("The name of the airport is \(airportName).") } else { print("That airport is not in the airports dictionary.") } // Prints "The name of the airport is Dublin Airport."
1 2 3 4
airports["APL"] = "Apple International" // "Apple International" is not the real airport for APL, so delete it airports["APL"] = nil// 删除 // APL has now been removed from the dictionary
1 2 3 4 5 6 7
// removeValue删除,返回删除元素可选值,用来确认是否有删除操作 iflet removedValue = airports.removeValue(forKey: "DUB") { print("The removed airport's name is \(removedValue).") } else { print("The airports dictionary does not contain a value for DUB.") } // Prints "The removed airport's name is Dublin Airport."
迭代字典
1 2 3 4 5 6
// 用元组迭代key和value for (airportCode, airportName) in airports { print("\(airportCode): \(airportName)") } // YYZ: Toronto Pearson // LHR: London Heathrow
1 2 3 4 5 6 7 8 9 10 11 12
// 也可以单独迭代key,value for airportCode in airports.keys { print("Airport code: \(airportCode)") } // Airport code: YYZ // Airport code: LHR for airportName in airports.values { print("Airport name: \(airportName)") } // Airport name: Toronto Pearson // Airport name: London Heathrow
1 2 3 4 5
let airportCodes = [String](airports.keys) // 字典的keys转数组 // airportCodes is ["YYZ", "LHR"] let airportNames = [String](airports.values) // airportNames is ["Toronto Pearson", "London Heathrow"] // 字典的values转数组
控制流
For-In循环
1 2 3 4 5 6 7 8 9
// 区间 for index in1...5 { print("\(index) times 5 is \(index * 5)") } // 1 times 5 is 5 // 2 times 5 is 10 // 3 times 5 is 15 // 4 times 5 is 20 // 5 times 5 is 25
1 2 3 4 5 6 7 8 9
let base = 3 let power = 10 var answer = 1 // 不用值的时候可以用_无视掉 for_in1...power { answer *= base } print("\(base) to the power of \(power) is \(answer)") // Prints "3 to the power of 10 is 59049"
1 2 3 4 5 6 7 8 9
let names = ["Anna", "Alex", "Brian", "Jack"] // 数组 for name in names { print("Hello, \(name)!") } // Hello, Anna! // Hello, Alex! // Hello, Brian! // Hello, Jack!
1 2 3 4 5 6 7 8
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] // 字典用元组来循环取值 for (animalName, legCount) in numberOfLegs { print("\(animalName)s have \(legCount) legs") } // ants have 6 legs // spiders have 8 legs // cats have 4 legs
While循环
有两种:
while 条件前置
repeat-while 条件后置
While
略
Repeat-while
略
条件语句
If
1 2 3 4 5
var temperatureInFahrenheit = 30 if temperatureInFahrenheit <= 32 { print("It's very cold. Consider wearing a scarf.") } // Prints "It's very cold. Consider wearing a scarf."
If-else
1 2 3 4 5 6 7
temperatureInFahrenheit = 40 if temperatureInFahrenheit <= 32 { print("It's very cold. Consider wearing a scarf.") } else { print("It's not that cold. Wear a t-shirt.") } // Prints "It's not that cold. Wear a t-shirt."
If-else if-else
1 2 3 4 5 6 7 8 9 10
temperatureInFahrenheit = 90 if temperatureInFahrenheit <= 32 { print("It's very cold. Consider wearing a scarf.") } elseif temperatureInFahrenheit >= 86 { print("It's really warm. Don't forget to wear sunscreen.") } else { print("It's not that cold. Wear a t-shirt.") } // Prints "It's really warm. Don't forget to wear sunscreen."
else可以省略
1 2 3 4 5 6
temperatureInFahrenheit = 72 if temperatureInFahrenheit <= 32 { print("It's very cold. Consider wearing a scarf.") } elseif temperatureInFahrenheit >= 86 { print("It's really warm. Don't forget to wear sunscreen.") }
Switch
switch必须包含所有的条件语句,如果想要一个类似其他的条件,可以提供一个default语句。
switch默认是每个分支执行后跳出的,不需要break
1 2 3 4 5 6 7 8 9 10
let someCharacter: Character = "z" switch someCharacter { case"a": print("The first letter of the alphabet") case"z": print("The last letter of the alphabet") default: print("Some other character") } // Prints "The last letter of the alphabet"
每个switch语句分支必须包含至少一条可执行语句。
比如下面的下是不对的:
1 2 3 4 5 6 7 8 9
let anotherCharacter: Character = "a" switch anotherCharacter { case"a": // 这里错误,至少需要一条可执行语句 Invalid, the case has an empty body case"A": print("The letter A") default: print("Not the letter A") } // This will report a compile-time error.
1 2 3 4 5 6 7 8 9
let anotherCharacter: Character = "a" // 一个case可以包含多个条件 switch anotherCharacter { case"a", "A": print("The letter A") default: print("Not the letter A") } // Prints "The letter A"
let approximateCount = 62 let countedThings = "moons orbiting Saturn" var naturalCount: String // case可以进行区间匹配 switch approximateCount { case0: naturalCount = "no" case1..<5: naturalCount = "a few" case5..<12: naturalCount = "several" case12..<100: naturalCount = "dozens of" case100..<1000: naturalCount = "hundreds of" default: naturalCount = "many" } print("There are \(naturalCount) \(countedThings).") // Prints "There are dozens of moons orbiting Saturn."
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let somePoint = (1, 1) // case也可以进行元组匹配 switch somePoint { case (0, 0): // 匹配原点 print("(0, 0) is at the origin") case (_, 0): // 匹配y轴 print("(\(somePoint.0), 0) is on the x-axis") case (0, _): // 匹配x轴 print("(0, \(somePoint.1)) is on the y-axis") case (-2...2, -2...2): // 匹配区域 print("(\(somePoint.0), \(somePoint.1)) is inside the box") default: // 其他 print("(\(somePoint.0), \(somePoint.1)) is outside of the box") } // Prints "(1, 1) is inside the box"
1 2 3 4 5 6 7 8 9 10 11
let anotherPoint = (2, 0) // case语句可以绑定值 switch anotherPoint { case (let x, 0): print("on the x-axis with an x value of \(x)") case (0, let y): print("on the y-axis with a y value of \(y)") caselet (x, y): print("somewhere else at (\(x), \(y))") } // Prints "on the x-axis with an x value of 2"
1 2 3 4 5 6 7 8 9 10 11
let yetAnotherPoint = (1, -1) // case语句可以包含一个where子句 switch yetAnotherPoint { caselet (x, y) where x == y: print("(\(x), \(y)) is on the line x == y") caselet (x, y) where x == -y: print("(\(x), \(y)) is on the line x == -y") caselet (x, y): print("(\(x), \(y)) is just some arbitrary point") } // Prints "(1, -1) is on the line x == -y"
1 2 3 4 5 6 7 8 9 10 11 12
let someCharacter: Character = "e" // 混合case语句,一个case可以包含多个条件 switch someCharacter { case"a", "e", "i", "o", "u": print("\(someCharacter) is a vowel") case"b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": print("\(someCharacter) is a consonant") default: print("\(someCharacter) is not a vowel or a consonant") } // Prints "e is a vowel"
1 2 3 4 5 6 7 8 9
let stillAnotherPoint = (9, 0) // 混合的元组case switch stillAnotherPoint { case (letdistance, 0), (0, letdistance): print("On an axis, \(distance) from the origin") default: print("Not on an axis") } // Prints "On an axis, 9 from the origin"
控制转移语句
continue
break
fallthrough
return
throw
Continue
跳过本次循环
1 2 3 4 5 6 7 8 9 10 11 12
let puzzleInput = "great minds think alike" var puzzleOutput = "" for character in puzzleInput.characters { switch character { case"a", "e", "i", "o", "u", " ": continue default: puzzleOutput.append(character) } } print(puzzleOutput) // Prints "grtmndsthnklk"
let numberSymbol: Character = "三"// Chinese symbol for the number 3 var possibleIntegerValue: Int? switch numberSymbol { case"1", "١", "一", "๑": possibleIntegerValue = 1 case"2", "٢", "二", "๒": possibleIntegerValue = 2 case"3", "٣", "三", "๓": possibleIntegerValue = 3 case"4", "٤", "四", "๔": possibleIntegerValue = 4 default: break } iflet integerValue = possibleIntegerValue { print("The integer value of \(numberSymbol) is \(integerValue).") } else { print("An integer value could not be found for \(numberSymbol).") } // Prints "The integer value of 三 is 3."
Fallthrough
switch默认是不会跳到下个分支去的,可以用fallthrough来强制进入下个分支。
1 2 3 4 5 6 7 8 9 10 11
let integerToDescribe = 5 var description = "The number \(integerToDescribe) is" switch integerToDescribe { case2, 3, 5, 7, 11, 13, 17, 19: description += " a prime number, and also" fallthrough default: description += " an integer." } print(description) // Prints "The number 5 is a prime number, and also an integer."
funcgreet(person: [String: String]) { guardlet name = person["name"] else { return } print("Hello \(name)!") guardlet location = person["location"] else { print("I hope the weather is nice near you.") return } print("I hope the weather is nice in \(location).") } greet(person: ["name": "John"]) // Prints "Hello John!" // Prints "I hope the weather is nice near you." greet(person: ["name": "Jane", "location": "Cupertino"]) // Prints "Hello Jane!" // Prints "I hope the weather is nice in Cupertino."
检查api的可用性
1 2 3 4 5
if #available(iOS 10, macOS 10.12, *) { // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS } else { // Fall back to earlier iOS and macOS APIs }
函数
定义与调用函数
1 2 3 4
funcgreet(person: String) -> String { let greeting = "Hello, " + person + "!" return greeting }
1 2 3 4 5 6 7
print(greet(person: "Anna")) // Prints "Hello, Anna!" print(greet(person: "Brian")) // Prints "Hello, Brian!"print(greet(person: "Anna")) // Prints "Hello, Anna!" print(greet(person: "Brian")) // Prints "Hello, Brian!"
// 函数的返回值可以无视 funcprintAndCount(string: String) -> Int { print(string) return string.characters.count } funcprintWithoutCounting(string: String) { let_ = printAndCount(string: string) } printAndCount(string: "hello, world") // prints "hello, world" and rturns a value of 12 printWithoutCounting(string: "hello, world") // prints "hello, world" but does not return a value
返回多个返回值的函数
1 2 3 4 5 6 7 8 9 10 11 12 13
// 可以用元组返回多个值 funcminMax(array: [Int]) -> (min: Int, max: Int) { var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } elseif value > currentMax { currentMax = value } } return (currentMin, currentMax) }
1 2 3
let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) print("min is \(bounds.min) and max is \(bounds.max)") // Prints "min is -6 and max is 109"
可选元组返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 当数组为空,返回nil。所以返回值是一个可选值 funcminMax(array: [Int]) -> (min: Int, max: Int)? { if array.isEmpty { returnnil } var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } elseif value > currentMax { currentMax = value } } return (currentMin, currentMax) }
1 2 3 4
iflet bounds = minMax(array: [8, -6, 2, 109, 3, 71]) { print("min is \(bounds.min) and max is \(bounds.max)") } // Prints "min is -6 and max is 109"
函数的实参标签与形参名
实参标签 用于调用函数
形参名 用于函数内部实现
1 2 3 4 5 6
// 默认的情况下,实参标签就是他们的形参名 funcsomeFunction(firstParameterName: Int, secondParameterName: Int) { // In the function body, firstParameterName and secondParameterName // refer to the argument values for the first and second parameters. } someFunction(firstParameterName: 1, secondParameterName: 2)
定义实参标签
1 2 3 4 5 6
// from就是实参标签,调用函数的时候会用到 funcgreet(person: String, from hometown: String) -> String { return"Hello \(person)! Glad you could visit from \(hometown)." } print(greet(person: "Bill", from: "Cupertino")) // Prints "Hello Bill! Glad you could visit from Cupertino."
删除实参标签
1 2 3 4 5 6
// 用_来删除实参标签 funcsomeFunction(_ firstParameterName: Int, secondParameterName: Int) { // In the function body, firstParameterName and secondParameterName // refer to the argument values for the first and second parameters. } someFunction(1, secondParameterName: 2)
参数默认值
1 2 3 4 5 6 7
// 参数parameterWithDefault的默认值是12 funcsomeFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) { // In the function body, if no arguments are passed to the function // call, the value of parameterWithDefault is 12. } someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6 someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
可变个数参数
一个函数最多有一个可变个数参数
1 2 3 4 5 6 7 8 9 10 11 12
// 用...定义可变个数参数 funcarithmeticMean(_ numbers: Double...) -> Double { var total: Double = 0 for number in numbers { total += number } return total / Double(numbers.count) } arithmeticMean(1, 2, 3, 4, 5) // returns 3.0, which is the arithmetic mean of these five numbers arithmeticMean(3, 8.25, 18.75) // returns 10.0, which is the arithmetic mean of these three numbers
In-Out参数
函数的参数默认是常数,不能修改的,需要修改参数的时候,可以将参数定义为In-Out参数。
1 2 3 4 5
funcswapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA }
1 2 3 4 5
var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // Prints "someInt is now 107, and anotherInt is now 3
函数类型
函数都有他自己的类型,比如:
1 2 3 4 5 6
funcaddTwoInts(_ a: Int, _ b: Int) -> Int { return a + b } funcmultiplyTwoInts(_ a: Int, _ b: Int) -> Int { return a * b }
上面的两个函数有相同的类型
(Int, Int) -> Int
即接收两个整型参数并返回一个整型返回值。
1 2 3
funcprintHelloWorld() { print("hello, world") }
() -> Void表示无参数,无返回值的函数类型。
使用函数类型
1
var mathFunction: (Int, Int) -> Int = addTwoInts
1 2
print("Result: \(mathFunction(2, 3))") // Prints "Result: 5"
1 2 3
mathFunction = multiplyTwoInts print("Result: \(mathFunction(2, 3))") // Prints "Result: 6"
1 2
let anotherMathFunction = addTwoInts // 也可以使用类型推导 // anotherMathFunction is inferred to be of type (Int, Int) -> Int
var currentValue = 3 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // moveNearerToZero now refers to the stepBackward() function
1 2 3 4 5 6 7 8 9 10 11
print("Counting to zero:") // Counting to zero: while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!") // 3... // 2... // 1... // zero!
嵌套函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcchooseStepFunction(backward: Bool) -> (Int) -> Int { funcstepForward(input: Int) -> Int { return input + 1 } funcstepBackward(input: Int) -> Int { return input - 1 } return backward ? stepBackward : stepForward } var currentValue = -4 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // moveNearerToZero now refers to the nested stepForward() function while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!") // -4... // -3... // -2... // -1... // zero!
闭包
No.
Type
Detail
1
全局函数
就是有名字的闭包,而且不捕获任何值
2
嵌套函数
就是有名字的闭包,可以捕获包围函数的值
3
闭包表达式
轻量级的闭包,可以捕获包围块的值
闭包表达式
Sorted方法
Swift标准库提供了一个排序方法用来给数组排序,排序基于接收的闭包参数。
1
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
funcsomeFunctionThatTakesAClosure(closure: () -> Void) { // function body goes here } // Here's how you call this function without using a trailing closure: // 可以用普通闭包写法 someFunctionThatTakesAClosure(closure: { // closure's body goes here }) // Here's how you call this function with a trailing closure instead: // 尾闭包写法 someFunctionThatTakesAClosure() { // trailing closure's body goes here }
let strings = numbers.map { (number) -> Stringin var number = number var output = "" repeat { output = digitNames[number % 10]! + output number /= 10 } while number > 0 return output } // strings is inferred to be of type [String] // its value is ["OneSix", "FiveEight", "FiveOneZero"]
捕获值
闭包可以捕获包围块的常量与变量,即使原范围的值已经不存在了。
1 2 3 4 5 6 7 8
funcmakeIncrementer(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 funcincrementer() -> Int { runningTotal += amount // 捕获runningTotal变量 return runningTotal } return incrementer }
1 2
// 调用函数后返回闭包,此闭包捕获了一个变量 let incrementByTen = makeIncrementer(forIncrement: 10)
1 2 3 4 5 6
incrementByTen() // returns a value of 10 返回10 incrementByTen() // returns a value of 20 返回20 incrementByTen() // returns a value of 30 返回30
1 2 3 4
// 调用函数后返回闭包,此闭包也捕获了一个变量 let incrementBySeven = makeIncrementer(forIncrement: 7) incrementBySeven() // returns a value of 7 返回7
1 2 3
// 不同的闭包捕获的变量不同 incrementByTen() // returns a value of 40 返回40
闭包是引用类型
1 2 3
let alsoIncrementByTen = incrementByTen alsoIncrementByTen() // returns a value of 50 返回50
directionToHead = .south switch directionToHead { case .north: print("Lots of planets have a north") case .south: print("Watch out for penguins") case .east: print("Where the sun rises") case .west: print("Where the skies are blue") } // Prints "Watch out for penguins"
1 2 3 4 5 6 7 8
let somePlanet = Planet.earth switch somePlanet { case .earth: print("Mostly harmless") default: print("Not a safe place for humans") } // Prints "Mostly harmless"
关联值
枚举量可以关联值。
1 2 3 4
enumBarcode{ case upc(Int, Int, Int, Int) case qrCode(String) }
1
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
1
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
1 2 3 4 5 6 7
switch productBarcode { case .upc(let numberSystem, let manufacturer, let product, let check): print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).") case .qrCode(let productCode): print("QR code: \(productCode).") } // Prints "QR code: ABCDEFGHIJKLMNOP."
// 字符串型的枚举的raw值是枚举case名。 enumCompassPoint: String{ case north, south, east, west }
1 2 3 4 5
let earthsOrder = Planet.earth.rawValue // earthsOrder is 3 let sunsetDirection = CompassPoint.west.rawValue // sunsetDirection is "west"
从raw值初始化枚举
1 2 3
// 由于从raw值初始化枚举不一定成功,所以返回的是枚举的可选类型 let possiblePlanet = Planet(rawValue: 7) // possiblePlanet is of type Planet? and equals Planet.uranus
1 2 3 4 5 6 7 8 9 10 11 12
let positionToFind = 11 iflet somePlanet = Planet(rawValue: positionToFind) { switch somePlanet { case .earth: print("Mostly harmless") default: print("Not a safe place for humans") } } else { print("There isn't a planet at position \(positionToFind)") } // Prints "There isn't a planet at position 11"
// 也可以加在enum前面 indirectenumArithmeticExpression{ case number(Int) case addition(ArithmeticExpression, ArithmeticExpression) case multiplication(ArithmeticExpression, ArithmeticExpression) }
1 2 3 4
let five = ArithmeticExpression.number(5) let four = ArithmeticExpression.number(4) let sum = ArithmeticExpression.addition(five, four) let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
classSomeClass{ // class definition goes here } structSomeStructure{ // structure definition goes here }
1 2 3 4 5 6 7 8 9 10
structResolution{ var width = 0 var height = 0 } classVideoMode{ var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
类和结构体的实例
1 2
let someResolution = Resolution() let someVideoMode = VideoMode()
访问属性
1 2
print("The width of someResolution is \(someResolution.width)") // Prints "The width of someResolution is 0"
1 2
print("The width of someVideoMode is \(someVideoMode.resolution.width)") // Prints "The width of someVideoMode is 0"
1 2 3
someVideoMode.resolution.width = 1280 print("The width of someVideoMode is now \(someVideoMode.resolution.width)") // Prints "The width of someVideoMode is now 1280"
按成员初始化结构体
1
let vga = Resolution(width: 640, height: 480)
结构体与枚举都是值类型
也就是说,赋予变量或常量,还有传递给函数,都是原始值的副本。 比如:
1 2
let hd = Resolution(width: 1920, height: 1080) var cinema = hd // 复制结构体
1
cinema.width = 2048// 改变其中一个的值
1 2
print("cinema is now \(cinema.width) pixels wide") // 值已改变 // Prints "cinema is now 2048 pixels wide"
1 2
print("hd is still \(hd.width) pixels wide") // 复制的结构体没有变,说明确实是两个实例 // Prints "hd is still 1920 pixels wide"
枚举也是一样,是值类型
1 2 3 4 5 6 7 8 9 10
enumCompassPoint{ case north, south, east, west } var currentDirection = CompassPoint.west let rememberedDirection = currentDirection currentDirection = .east if rememberedDirection == .west { print("The remembered direction is still .west") } // Prints "The remembered direction is still .west"
类是引用类型
不同于值类型,类在赋予变量或常量,还有传递给函数的时候都是引用的同一个实例。 比如:
1 2 3 4 5
let tenEighty = VideoMode() tenEighty.resolution = hd tenEighty.interlaced = true tenEighty.name = "1080i" tenEighty.frameRate = 25.0
1 2
let alsoTenEighty = tenEighty // 复制类引用 alsoTenEighty.frameRate = 30.0// 改变引用类的值
1 2
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)") // 可以看到原值也被改变了,说明指向是同一个 // Prints "The frameRate property of tenEighty is now 30.0"
相同性操作符
由于类是引用类型,所以swift提供类两个相同性操作符来比较两个实例是否指向同一个对象。
=== 相同
!== 不相同
1 2 3 4
if tenEighty === alsoTenEighty { print("tenEighty and alsoTenEighty refer to the same VideoMode instance.") } // Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
注意不要写成==。
指针
略
选择类还是结构体
略
字符串,数组,字典的赋值与复制
在swift中字符串,数组,字典是结构体。 所以赋值与赋值的时候会生成一个副本。
属性
属性是类,结构体,枚举的关联值。
存储属性 可以存储值
计算属性 不能存储值,只能提供一个计算后的值
存储属性与计算属性的支持性
类型
存储属性
计算属性
类
✅
✅
结构体
✅
✅
枚举
❌
✅
存储属性
可以是变量,也可以是常量。
1 2 3 4 5 6 7 8
structFixedLengthRange{ var firstValue: Int let length: Int } var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // the range represents integer values 0, 1, and 2 rangeOfThreeItems.firstValue = 6 // the range now represents integer values 6, 7, and 8
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) // this range represents integer values 0, 1, 2, and 3 rangeOfFourItems.firstValue = 6// 这里会报错 // this will report an error, even though firstValue is a variable property
延迟创建的存储属性
用lazy可以定义一个延迟创建的属性。 这个属性会在第一次使用的时候才创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classDataImporter{ /* DataImporter is a class to import data from an external file. The class is assumed to take a non-trivial amount of time to initialize. */ var fileName = "data.txt" // the DataImporter class would provide data importing functionality here } classDataManager{ lazyvar importer = DataImporter() var data = [String]() // the DataManager class would provide data management functionality here } let manager = DataManager() // 此时DataImporter还没有被创建 manager.data.append("Some data") manager.data.append("Some more data") // the DataImporter instance for the importer property has not yet been created
1 2 3
print(manager.importer.fileName) // 第一次调用DataImporter的时候创建 // the DataImporter instance for the importer property has now been created // Prints "data.txt"
classStepCounter{ var totalSteps: Int = 0 { willSet(newTotalSteps) { print("About to set totalSteps to \(newTotalSteps)") } didSet { if totalSteps > oldValue { print("Added \(totalSteps - oldValue) steps") } } } } let stepCounter = StepCounter() stepCounter.totalSteps = 200 // About to set totalSteps to 200 // Added 200 steps stepCounter.totalSteps = 360 // About to set totalSteps to 360 // Added 160 steps stepCounter.totalSteps = 896 // About to set totalSteps to 896 // Added 536 steps
let counter = Counter() // the initial counter value is 0 counter.increment() // the counter's value is now 1 counter.increment(by: 5) // the counter's value is now 6 counter.reset() // the counter's value is now 0
self属性
每个实例方法都隐含有一个self属性,指向实例自身。 比如上述increment方法可以定义为:
1 2 3
funcincrement() { self.count += 1 }
self一般可以省略,不过与本地变量或者参数重名的时候不可以省略。
1 2 3 4 5 6 7 8 9 10 11
structPoint{ var x = 0.0, y = 0.0 funcisToTheRightOf(x: Double) -> Bool { returnself.x > x } } let somePoint = Point(x: 4.0, y: 5.0) if somePoint.isToTheRightOf(x: 1.0) { print("This point is to the right of the line where x == 1.0") } // Prints "This point is to the right of the line where x == 1.0"
在实例方法中修改值类型
实例方法默认是不能就该值类型的值的。 除非在实例方法前用mutating申明可变。
1 2 3 4 5 6 7 8 9 10 11
structPoint{ var x = 0.0, y = 0.0 mutatingfuncmoveBy(x deltaX: Double, y deltaY: Double) { x += deltaX y += deltaY } } var somePoint = Point(x: 1.0, y: 1.0) somePoint.moveBy(x: 2.0, y: 3.0) print("The point is now at (\(somePoint.x), \(somePoint.y))") // Prints "The point is now at (3.0, 4.0)"
需要注意的是,如果值类型是常量的话,即使是mutating方法也不能修改值。
1 2 3
let fixedPoint = Point(x: 3.0, y: 3.0) // 这里将报错 fixedPoint.moveBy(x: 2.0, y: 3.0) // this will report an error
在突变方法中给self赋值
突变方法就是定义为mutating的方法。 可以在突变方法中给self赋值。
1 2 3 4 5 6
structPoint{ var x = 0.0, y = 0.0 mutatingfuncmoveBy(x deltaX: Double, y deltaY: Double) { self = Point(x: x + deltaX, y: y + deltaY) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
enumTriStateSwitch{ case off, low, high mutatingfuncnext() { switchself { case .off: self = .low case .low: self = .high case .high: self = .off } } } var ovenLight = TriStateSwitch.low ovenLight.next() // ovenLight is now equal to .high ovenLight.next() // ovenLight is now equal to .off
类型方法
属于特定类型的方法。
1 2 3 4 5 6
classSomeClass{ classfuncsomeTypeMethod() { // type method implementation goes here } } SomeClass.someTypeMethod()
略
下标
类,结构体与枚举可以定义下标。
下标语法
1 2 3 4 5 6 7 8
subscript(index: Int) -> Int { get { // return an appropriate subscript value here } set(newValue) { // perform a suitable setting action here } }
1 2 3 4
// 定义只读的下标 subscript(index: Int) -> Int { // return an appropriate subscript value here }
下面看一个只读下标的实现。
1 2 3 4 5 6 7 8 9
structTimesTable{ let multiplier: Int subscript(index: Int) -> Int { return multiplier * index } } let threeTimesTable = TimesTable(multiplier: 3) print("six times three is \(threeTimesTable[6])") // Prints "six times three is 18"
let someValue = matrix[2, 2] // 将激活断言,报错 // this triggers an assert, because [2, 2] is outside of the matrix bounds
继承
略。
定义一个基础类
1 2 3 4 5 6 7 8 9
classVehicle{ var currentSpeed = 0.0 var description: String { return"traveling at \(currentSpeed) miles per hour" } funcmakeNoise() { // do nothing - an arbitrary vehicle doesn't necessarily make a noise } }
1
let someVehicle = Vehicle()
1 2
print("Vehicle: \(someVehicle.description)") // Vehicle: traveling at 0.0 miles per hour
子类
用:来继承。 语法
1 2 3
classSomeSubclass: SomeSuperclass{ // subclass definition goes here }
demo
1 2 3
classBicycle: Vehicle{ var hasBasket = false }
1 2
let bicycle = Bicycle() bicycle.hasBasket = true
1 2 3
bicycle.currentSpeed = 15.0 print("Bicycle: \(bicycle.description)") // Bicycle: traveling at 15.0 miles per hour
1 2 3 4
// 子类还可以被继承 classTandem: Bicycle{ var currentNumberOfPassengers = 0 }
1 2 3 4 5 6
let tandem = Tandem() tandem.hasBasket = true tandem.currentNumberOfPassengers = 2 tandem.currentSpeed = 22.0 print("Tandem: \(tandem.description)") // Tandem: traveling at 22.0 miles per hour
let automatic = AutomaticCar() automatic.currentSpeed = 35.0 print("AutomaticCar: \(automatic.description)") // AutomaticCar: traveling at 35.0 miles per hour in gear 4
阻止重写
用final关键字可以防止被重写。
初始化
初始化是指准备实例化类,结构体,枚举的过程。
为存储属性设置初始值
类和结构体初始化的时候,必须为所有的存储属性设置合适的初始值。
可以在初始化方法中为存储属性设置初始值,也可以为存储属性设置默认值。
初始化方法
即实例化的时候调用的方法。
语法:
1 2 3
init() { // perform some initialization here }
demo:
1 2 3 4 5 6 7 8 9
structFahrenheit{ var temperature: Double init() { temperature = 32.0 } } var f = Fahrenheit() print("The default temperature is \(f.temperature)° Fahrenheit") // Prints "The default temperature is 32.0° Fahrenheit"
属性默认值
在存储属性定义的时候直接可以赋与一个默认值。
1 2 3
structFahrenheit{ var temperature = 32.0 }
自定义初始化方法
初始化参数
1 2 3 4 5 6 7 8 9 10 11 12 13
structCelsius{ var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } } let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) // boilingPointOfWater.temperatureInCelsius is 100.0 let freezingPointOfWater = Celsius(fromKelvin: 273.15) // freezingPointOfWater.temperatureInCelsius is 0.0
参数名与实参标签
由于初始化函数的实参标签比较重要,所以如果没有设置的话,swift会自动设置。
1 2 3 4 5 6 7 8 9 10 11 12 13
structColor{ let red, green, blue: Double init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } init(white: Double) { red = white green = white blue = white } }
1 2
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) let halfGray = Color(white: 0.5)
structCelsius{ var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } // 用_来忽视掉实参标签 init(_ celsius: Double) { temperatureInCelsius = celsius } } let bodyTemperature = Celsius(37.0) // bodyTemperature.temperatureInCelsius is 37.0 #### 可选类型的属性类型 如果一个属性逻辑上允许为nil,那么在初始化过程中可以不赋值。因为自动初始化为nil。 ```swift classSurveyQuestion{ var text: String var response: String? init(text: String) { self.text = text } funcask() { print(text) } } let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") cheeseQuestion.ask() // Prints "Do you like cheese?" cheeseQuestion.response = "Yes, I do like cheese."
初始化中常量属性的赋值
在初始化过程中可以给常量赋值,而一旦赋值就不再能修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSurveyQuestion{ let text: String var response: String? init(text: String) { self.text = text } funcask() { print(text) } } let beetsQuestion = SurveyQuestion(text: "How about beets?") beetsQuestion.ask() // Prints "How about beets?" beetsQuestion.response = "I also like beets. (But not with cheese.)"
默认初始化函数
swift为没有提供初始化函数的类和结构体提供了默认的初始化函数。
1 2 3 4 5 6
classShoppingListItem{ var name: String? var quantity = 1 var purchased = false } var item = ShoppingListItem()
结构体的默认初始化函数
1 2 3 4
structSize{ var width = 0.0, height = 0.0 } let twoByTwo = Size(width: 2.0, height: 2.0)
值类型的初始化方法代理
1 2 3 4 5 6
structSize{ var width = 0.0, height = 0.0 } structPoint{ var x = 0.0, y = 0.0 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
structRect{ var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) // 用self.init使用初始化方法代理 } }
1 2
let basicRect = Rect() // basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
1 2 3
let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) // originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)
1 2 3
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)