首页 > 代码库 > Swift常用语法示例代码(一)
Swift常用语法示例代码(一)
此篇文章整理自我以前学习Swift时的一些练习代码,其存在的意义多是可以通过看示例代码更快地回忆Swift的主要语法。
如果你想系统学习Swift或者是Swift的初学者请绕路,感谢Github上The Swift Programming Language
开源翻译的中文版,感谢极客学院wiki提供的PDF版本。
代码和PDF版本上传至Github,有兴趣的可以下载下来试试。
SwiftTour
Base
var str = "Hello, World!"print(str)// 变量用var声明,常量用let声明,变量类型自动推断// 可在变量后声明类型,用冒号分隔var myVariable = 42let myConstant = 42myVariable = 50let explictDouble: Double = 60// 值永远不会被隐式转换为其他类型,需要转换必须采用显式转换let label = "The width is "let width = 94let widthLabel = label + String(width)// 更为常见的将值转换为字符串的方法let apples = 3let oranges = 5let appleSummary = "I have \(apples) apples"let fruitSummary = "I have \(apples + oranges) pieces of fruit"// []用来创建数组或字典var shoppingList = ["catfish", "water", "tulips", "blue paint"]shoppingList[1] = "bottle of water"var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic"]occupations["Jayne"] = "Public Relations"// 创建一个空数组或者字典let emptyArray1 = [String]()let emptyDictionary1 = [String: Float]()let emptyArray2: [String] = []let emptyDictionary2: [String: Float] = [:]// 控制流,if和switch用于选择,for-in,for,while和repeat-while用于循环let individualScores = [75, 43, 103, 87, 12]var teamScore = 0for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 }}print(teamScore)// 由于不支持隐式转换,条件必须是一个布尔表达式// 一般采用可选值配合if和let,处理值缺失判断var optionalString: String? = "Hello"print(optionalString == nil)var optionalName: String? = "John Appleseed"var greeting = "Hello"if let name = optionalName { greeting = "Hello, \(name)"}// Switch支持任意类型的数据以及各种比较操作let vegetable = "red pepper"switch vegetable {case "celery" : print("Add some raisins and make ants on a log")case "cucumber", "watercress" : print("That woould make a good tea sandwich")case let x where x.hasSuffix("pepper") : print("Is it a spicy \(x)?")default : print("Everything tastes good in soup")}// 使用for-in遍历字典let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25],]var largest = 0var numberGroup: String = "Null"for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number numberGroup = kind } }}print(numberGroup, largest)// while循环var n = 2while n \< 100 { n = n * 2}print(n)var m = 2repeat { m = m * 2} while m \< 100print(m)// 可以在循环中使用..\<来表示范围,包含上界使用...var firstForLoop = 0for i in 0..\<4 { firstForLoop += i}print(firstForLoop)var secondForLoop = 0for var i = 0; i \< 4; ++i { secondForLoop += i}print(secondForLoop)
函数
// 使用func来声明函数,尾置返回func greet(name: String, day: String) -\>String { return "Hello \(name), today is \(day)"}greet("Bob", day: "Tuesday")// 使用元组来让函数返回多个值func calculateStatistics(scores: [Int])-\>(min: Int, max: Int, sum: Int) { var min = scores[0] var max = scores[0] var sum = 0 for score in scores { if score > max { max = score } else if score < min { min = score } sum += score } return (min, max, sum)}let statistics = calculateStatistics([5, 3, 100, 3, 9])print(statistics.sum)// 函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式func sumOf(numbers: Int...)-\>Int { var sum = 0 for number in numbers { sum += number } return sum}sumOf()sumOf(42, 597, 12)// 函数可以嵌套,被嵌套的函数可以访问外侧函数的变量func returnFifteen()-\>Int { var y = 10 func add() { y += 5 } add() return y}print(returnFifteen())// 函数是类型,也可以作为另外一个函数的返回值func makeIncrementer()-\>(Int -\> Int) { func addOne(number: Int)->Int { return 1 + number } return addOne}var increment = makeIncrementer()print(increment(7))// 函数也可以当做参数传入另外一个函数func hasAnyMatches(list: [Int], condition: Int -\> Bool)-\>Bool { for item in list { if condition(item) { return true } } return false}func lessThanTen(number: Int)-\>Bool { return number < 10}var numbers = [20, 19, 7, 12]hasAnyMatches(numbers, condition: lessThanTen)//闭包就是嵌套的匿名函数,{ in }let mappedNumbers = numbers.map({number in 3 \* number})print(mappedNumbers)let sortedNumbers = numbers.sort{$0 \< $1}print(sortedNumbers)
类和对象
// 使用class和类名创建一个类class Shape { var numberOfSides = 0 func simpleDescription() ->String { return "A Shape with \(numberOfSides) sides" }}var shape = Shape()shape.numberOfSides = 7var shapeDescription = shape.simpleDescription()// 使用init创建构造器,使用deinit创建一个析构函数class NameShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() ->String { return "A Shape with \(numberOfSides) sides" }}// 子类重写父类的方法需要用override标记class Squre: NameShape { var sideLength: Double init(sideLength: Double, name: String){ self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area()->Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)" }}let test = Squre(sideLength: 5.2, name: "My test Square")test.area()test.simpleDescription()// 类的getter和setterclass EquilateralTriangle: NameShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String){ self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triangle with sides of length \(sideLength)" }}var triangel = EquilateralTriangle(sideLength: 3.1, name: "a triangle")print(triangel.perimeter)triangel.perimeter = 9.9print(triangel.sideLength)// 不需要计算属性,仍然需要在设置新值之前或之后运行代码,使用willset和didset// 确保三角形的边长综合正方形的边长相同class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Squre { willSet { triangel.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Squre(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) }}var triangleAndSquare = TriangleAndSquare(size: 10, name: "Another tested Shape")print(triangleAndSquare.square.sideLength)print(triangleAndSquare.triangle.sideLength)triangleAndSquare.triangle = EquilateralTriangle(sideLength: 30, name: "Other")print(triangleAndSquare.triangle.sideLength)print(triangleAndSquare.square.sideLength)// 处理变量的可选值时,可以在操作前加?let optionalSquare: Squre? = Squre(sideLength: 2.5, name: "Optional square")let sideLength = optionalSquare?.sideLengthprint(sideLength)
枚举和结构体
import Foundation// 使用enum创建一个枚举,枚举可以包含方法enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription()->String { switch self { case .Ace: return "Ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.rawValue) } }}let ace = Rank.Tenlet aceRawValue = http://www.mamicode.com/ace.rawValue"hljs-built_in">print(aceRawValue)print(ace.simpleDescription())// 使用init?(rawValue:)初始化构造器在原始值和枚举值之间进行转换let c = Rank(rawValue: 34)print(c)if let convertedRank = Rank(rawValue: 3) { let threeDescription = convertedRank.simpleDescription()}// 可以不设置原始值,但系统会内部为枚举设置枚举值enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDecription()->String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } }}let hearts = Suit.Heartslet heartsDescription = hearts.simpleDecription()print(heartsDescription)// struct和class的区别是,结构体传值,类传引用struct Card { var rank: Rank var suit: Suit func simpleDescription()->String { return "The \(rank.simpleDescription()) of \(suit.simpleDecription())" }}let threeOfSpades = Card(rank: .Three, suit: .Spades)let threeOfSpadesDescription = threeOfSpades.simpleDescription()print(threeOfSpadesDescription)// 枚举成员的实例值enum ServerResponse { case Result(String,String) case Error(String)}let success = ServerResponse.Result("6:00", "9:00")let failure = ServerResponse.Error("Out of cheese")let success1 = ServerResponse.Result("8:00", "9:00")switch success1 {case let .Result(sunrise, sunset): let serverReponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)" print(serverReponse)case let .Error(error): let serverReponse = "Failure... \(error)" print(serverReponse)}
协议
import Foundation// 使用protocol来声明一个协议protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust()}// 类、枚举和结构题都可以实现协议class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class" var anotherProperty: Int = 69105 func adjust() { simpleDescription += "Now 100% adjusted" }}var a = SimpleClass()a.adjust()let aDescription = a.simpleDescriptionprint(aDescription)// mutating关键字标记一个会修改结构体的方法struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A very simple class" mutating func adjust() { simpleDescription += " (adjusted)" }}var b = SimpleStructure()b.adjust()let bDescription = b.simpleDescriptionprint(bDescription)// 使用extension来为现有的类型添加功能extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 }}print(7.simpleDescription)// 可以像使用其他类型一样使用协议名// 即使protocolValue变量运行时类型是simpleClass,编译器会把它的类型当作ExampleProtocol// 这意味着,不能调用类在它实现协议之外的方法或属性let protocolValue: ExampleProtocol = aprint(protocolValue.simpleDescription)// print(protocolValue.anotherProperty) //Error
泛型
import Foundation// 在尖括号里写一个名字来创建一个泛型函数或类型func repeatItem<Item>(item: Item, numberOfTimes: Int)-\>[Item] { var result = [Item]() for _ in 0..<numberOfTimes { result.append(item) } return result}let result = repeatItem("knock", numberOfTimes: 5)print(result)// 也可以穿件泛型函数、方法、类、枚举和结构体enum OptionalValue<Wrapped> { case None case Some(Wrapped)}var possibleInteger: OptionalValue<Int> = .NonepossibleInteger = .Some(3)// 在类型名后面使用where来指定对类型的需求// 比如,限定类型实现某一个协议,限定两个类型是相同的,或者限定某个类必须有一个特定的父类func anyCommonElements\<T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element\>(lhs: T, \_ rhs: U)-\>Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false}print(anyCommonElements([1, 2 ,3], [3]))
SwiftBasics
SwiftBasics是对Swift类型和变量的介绍,有过别的语言基础的扫一眼即可。需要注意的地方主要是可选类型和元组,这是Swift特有的类型。
import Foundation// Print(\_:,separator:,terminator:)print("Hello World", "iOS",separator: "\*", terminator: "")// 可以通过分号,实现一行写多条独立语句let cat = "Tom"; print("Hello \(cat)")// 可以访问不同整数类型的min和max属性来获取对应类型的最小值和最大值// Swift中的Int长度与当前平台有关,在32位平台Int与Int32长度相同,在64位平台Int与Int64长度相同print(Int8.max)print(Int8.min)print(Int.max)print(Int64.max)// 整数和浮点数都可以增加额外的零并且包含下划线,并不会影响字面值let oneMillion = 001\_000\_000print(oneMillion)// 数值类型的转换需要调用类型内置构造器// 可以通过扩展现有类型的构造器,使之接受更多的类型转换let one:UInt8 = 1let two:Int8 = 2let onePlusTwo = one + UInt8(two)print(onePlusTwo)// 可以把多个值组合成一个复合值,元组内的值可以是任意类型,并不要求是相同类型let http404Error = (404, "Not Found")print(http404Error)// 可以将一个元组的内容分解成单独的常量和变量print("The status code is \(http404Error.0)")let (statusCode, statusMessage) = http404Errorprint("The status message is \(statusMessage)")let (justTheStatusCode, \_) = http404Errorprint("The status code is \(justTheStatusCode)")// 在元组命名时对单个元素进行命名let http200Status = (statusCode: 200, statusMessage: "OK")print("The status code is \(http200Status.statusCode)")// 可选类型// 并不是所有对字符串都能转换为整数,Int构造器可能会失败,转换结果是可选类型let possibleNumber = "123"let convertedNumber = Int(possibleNumber)print(convertedNumber)// 可以通过nil给可选类型变量赋值,nil不可以用于非可选类型// 声明了一个可选类型变量没有赋值,系统会自动设置为nilvar serverReponseCode: Int? = 404serverReponseCode = nilvar surveyAnswer: String?// 可以使用相等不等符判断可选类型是否有值,当确定有值时,可以用!强制解析if convertedNumber != nil { print("convertedNumber contains some integer value of \(convertedNumber!)")}// 可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个临时常量或变量if let actualNumber = Int(possibleNumber) { print("\‘\(possibleNumber)\‘ has an integer value of \(actualNumber)")} else { print("\‘\(possibleNumber)\‘ could not be converted to an integer")}// 可以包含多个可选绑定在if语句中,并使用where子句做布尔值判断if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber \< secondNumber { print("\(firstNumber) < \(secondNumber)")}// 用!声明隐式解析可选类型// 隐式可选类型其实就是一个普通的可选类型,但是可以被当作非可选类型来使用,并不需要每次都解析可选值let possibleString: String? = "An optional string"let forcedString: String = possibleString!print(forcedString)let assumedString: String! = "An implicitly unwrapped optional string"let implicitString: String = assumedStringprint(implicitString)
SwiftBasicOperators
SwiftBasicOperators部分是对Swift支持的运算符的介绍。Swift支持大部分标准C语言的运算符,且改进许多特性来减少常规编码错误。如赋值符(=)不返回值,算术运算符会检测并不允许溢出。区别于C语言,在Swift中,你可以对浮点数取余运算(%)。此外,Swift还提供了C语言中没有的区间运算符(a..\<b和a...b)。
import Foundation// 如果赋值的右边是一个多元组,它的元素可以马上被分解成多个常量或变量let (x, y) = (1, 2)print(x, y)// 取余运算,对负数b求余时,b的符号会被忽略print(9 % 4)print(-9 % 4)print(9 % -4)// 浮点数求余print(8 % 2.5)// 一元负号和一元正号运算符写在操作数之前,中间没有空格// 注意的是,一元正号不做任何改变地返回操作数的值let minusSix = -6print(-minusSix)print(+minusSix)// 空合运算符 a ?? b// 表达式a必须是Optional类型,b的类型必须与a的存储值类型一致// 如果a为nil,则返回b的值。如果a有值,则返回a的解析值。// 并不会改变a和b的值let defaultColorName = "red"var userDefinedColorName: String?var colorNameToUse = userDefinedColorName ?? defaultColorNameprint(colorNameToUse, userDefinedColorName)userDefinedColorName = "grren"colorNameToUse = userDefinedColorName ?? defaultColorNameprint(colorNameToUse, userDefinedColorName)// 区间运算符for index in 1...5 { print("\(index) * 5 = \(index * 5)")}let names = ["Anna", "Alex", "Brain", "Jack"]let count = names.countfor i in 0..\<count { print("第\(i)个人叫\(names[i])")}
SwiftStrings
SwiftStrings部分主要介绍Swift字符串与字符。Swift的String和Character类型提供了一种快速的兼容Unicode的方式处理文本,字符串的每个字符都是Unicode字符,支持访问Unicode的不同表示形式。
import Foundation// 每个字符串都是由编码无关的Unicode字符组成// 创建一个空字符串var emptyString = ""var anotherEmptyString = String()// 通过isEmpty属性来判断字符串是否为空if emptyString.isEmpty { print("Nothing to see here")}// 通过for-in循环遍历字符串的characters属性来获取每个字符的值for character in "Dog!".characters { print(character)}// 字符串可以通过character字符数组初始化let catCharacters:[Character] = ["C", "a", "t"]let catString = String(catCharacters)print(catString)// 连接字符串let string1 = "Hello "let string2 = "there"var welcome = string1 + string2let exclamationMark: Character = "!"welcome.append(exclamationMark)print(welcome)// \u{}表示Unicode字符,注意大括号里面的数值是十六进制let dollarSign = "\u{24}"let blackHeart = "\u{2665}"let sparklingHeart = "\u{1F496}"print(dollarSign, blackHeart, sparklingHeart)// Swift字符Character是采用可扩展字符集,即有的字符是由多个Unicode字符组合而成let exampleCharacter1 = "\u{1112}\u{1161}\u{11AB}"let exampleCharacter2 = "\u{D55C}"print(exampleCharacter1,exampleCharacter2)// 字符串的characters.count方法计算的是字符串有多少字符组成let unusualMenagerie = "Koala\u{1F1FA}\u{1F1F8}"print(unusualMenagerie)print(unusualMenagerie.characters.count)var word = "cafe"print("the number of characters in \(word) is \(word.characters.count)")word += "\u{301}"print("the number of characters in \(word) is \(word.characters.count)")// 字符串索引,String.Index,不支持整数做索引// predecessor()取前一个索引,successor()取后一个索引// advancedBy()获取索引// 越界会引发运行时候错误let greeting = "Guten Tag!"print(greeting[greeting.startIndex])print(greeting[greeting.endIndex.predecessor()])print(greeting[greeting.startIndex.successor()])let index = greeting.startIndex.advancedBy(7)print(greeting[index])print(word[greeting.startIndex])print(greeting[index.advancedBy(1)])print(greeting[index.advancedBy(2, limit: greeting.endIndex)])// 使用characters属性的indices属性会创建一个包含所有索引的范围for index in greeting.characters.indices { print("\(greeting[index])", terminator: " ")}// 调用insert()插入元素// 调用insertContentsOf()插入字符串welcome.insert("!", atIndex: welcome.endIndex)print(welcome)welcome.insertContentsOf("here".characters, at: welcome.endIndex.predecessor())print(welcome)// removeAtIndex()删除索引指定的元素// removeRange()删除索引范围元素welcome.removeAtIndex(welcome.endIndex.predecessor())print(welcome)welcome.removeRange(welcome.endIndex.advancedBy(-4)..\<welcome.endIndex)print(welcome)// 调用hasPrefix()判断是否包含指定前缀// 调用hasSuffix()判断是否包含指定后缀let prefixAndSuffix = ["abc123", "absfeh23", "23"]var prefix = 0var suffix = 0for i in prefixAndSuffix { if i.hasPrefix("ab") { prefix++ } if i.hasSuffix("23") { suffix++ }}print(prefix, suffix)//Unicode编码形式,UTF-8(编码字符串为8位),UTF-16,UTF-32let dogString = "Dog!??"for codeUnit in dogString.utf8 { print("\(codeUnit)", terminator: " ")}print("")for codeUnit in dogString.unicodeScalars { print("\(codeUnit.value)", terminator: " ")}print("")for codeUnit in dogString.unicodeScalars { print("\(codeUnit)", terminator: " ")}print("")print(dogString.utf8.count)print(dogString.utf16.count)print(dogString.unicodeScalars.count)// 字符串比较时需注意// 两个字符,即便构成它们的Unicode标量不同,只要它们拥有同样的语言意义和外观,就认为它们相等let s1 = "caf\u{E9}"let s2 = "caf\u{65}\u{301}"print(s1, s2)if s1 == s2 { print("equal string")}
SwiftCollectionTypes
SwiftCollection部分主要介绍Swift中的三种集合类型Array、Set、Dictionary,Swift中集合类型封装了很多属性和方法,语法特性都与C语言有较大的区别。
Array
import Foundation// Swift提供Array、Set、Dictionary三种集合类型// 创建一个空数组// 如果创建时数组类型已知,可以直接用[]定义一个空数组var someInts = [Int]()someInts.append(3)someInts = []// 创建特定大小并且所有数据都被初始化var threeDoubles = [Double](count: 3, repeatedValue: 0.0)// 通过两个数组相加创建一个数组var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)var sixDoubles = threeDoubles + anotherThreeDoublesprint(sixDoubles)// 用字面值构造数组var shoppingList1: [String] = ["Eggs", "Milk"]var shoppingList2 = ["Eggs", "Milk"]// count属性、isEmpty属性// append()方法if shoppingList1.isEmpty { print("Array is empty")} else { print("not empty, count \(shoppingList1.count)")}shoppingList1.append("shoes")shoppingList1 += ["water"]print(shoppingList1)// 允许使用整数索引print(shoppingList1[0])shoppingList1[0] = "six eggs"shoppingList1[1...3] = ["Bananas", "Apples"]print(shoppingList1)// insert()和removeAtIndex()shoppingList1.insert("Maple Syrup", atIndex: 0)let mapleSyrup = shoppingList1.removeAtIndex(0)print(mapleSyrup, shoppingList1)let apples = shoppingList1.removeLast()print(apples, shoppingList1)// for-in遍历for item in shoppingList1 { print(item)}// enumerate()方法遍历,返回每个数组元素索引值和元素值组成的元组for (index, value) in shoppingList1.enumerate() { print("Item \(index+1): \(value)")}
Set
// 集合(Set)存储相同类型并且没有确定顺序的值。适用于元素顺序不重要或者希望元素只出现一次// 集合只能存储可哈希化的类型,哈希值是Int类型的,相等的对象哈希值必须相同// 自定义的类型作为集合的值或者字典的Key,自定义的类型需符合Hashable协议,提供一个类型位Int的可读属性hashValue// 因为Hashable协议符合Equatable协议,所以符合该协议的类型也必须提供一个是否相等(==)运算符的实现// 创建一个空的集合var letters = Set<Character>()letters.insert("a")letters = []print(letters)// 用数组初始化集合,需要显式声明集合的类型,元素类型可以从数组中推断var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]// count、isEmpty属性if !favoriteGenres.isEmpty { print(favoriteGenres.count)}// insert方法favoriteGenres.insert("Jazz")// remove方法// 如果该值是集合的元素,删除值,返回删除值。如果不是集合的元素,则返回nilif let removedGenre = favoriteGenres.remove("Rock") { print(removedGenre)} else { print("nil")}// contains()方法检查Set中是否包含一个特定的值if favoriteGenres.contains("Funk") { print("I get up on the good foot")} else { print("It‘s too funky in here")}// for-in遍历一个Setfor genre in favoriteGenres { print(genre)}// Set没有确定的顺序,但可以利用sort方法返回一个有序集合for genre in favoriteGenres.sort() { print(genre)}// Set支持高效的集合操作let oddDigits: Set = [1, 3, 5, 7, 9]let evenDigits: Set = [0, 2, 4, 6, 8]let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]print(oddDigits.union(evenDigits).sort())print(oddDigits.intersect(evenDigits).sort())print(oddDigits.subtract(singleDigitPrimeNumbers).sort())print(oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort())// Set关系let houseAnimals: Set = ["??", "??"]let farmAnimals: Set = ["??", "??", "??", "??", "??"]let cityAnimals: Set = ["??", "??"]print(houseAnimals.isSubsetOf(farmAnimals))print(farmAnimals.isSupersetOf(houseAnimals))print(farmAnimals.isDisjointWith(cityAnimals))print(houseAnimals.isStrictSubsetOf(houseAnimals))print(houseAnimals.isSubsetOf(houseAnimals))
Dictionary
// 字典是储存相同类型的容器,每个值都关联唯一的键值(key),与数组不同的是,字典的数据项目没有具体顺序// 创建一个空字典var namesOfIntegers = [Int: String]()namesOfIntegers[16] = "sixteen"namesOfIntegers = [:]// 用字典字面值创建字典,字典类型可由字面值推断// var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]// count、isEmpty属性if !airports.isEmpty { print(airports.count)}// 使用下标语法增加数据项airports["LHR"] = "London"airports["LHR"] = "London Heathrow"// updateValue()方法更新Key对应的值或者创建新Key// 返回更新之前的原值或nilif let oldValue = http://www.mamicode.com/airports.updateValue("Dublin Airport", forKey: "DUB") { print(oldValue)}// 下标语法方式也返回可选值if let airportName = airports["CHZ"] { print(airportName)} else { print("The airport is not in the dictionary")}print(airports)// 通过下标语法给某个键赋值为nil来从字典中删除一对键值airports["APL"] = "Apple"airports["APL"] = nilprint(airports)// removeValueForKey()方法// 如果删除的Key存在,删除该键值,返回删除值。如果删除的Key不存在,返回nilif let removedValue = http://www.mamicode.com/airports.removeValueForKey("DUB") { print(removedValue)}// for-in遍历,返回(key, value)元组for (airportCode, airportName) in airports { print("\(airportCode): \(airportName)")}// 通过访问keys或者values属性,我们也可以遍历字典的键或值for airportCode in airports.keys { print(airportCode)}// 使用keys或者values属性构造一个数组let airportCodes = [String][8]print(airportCodes)// 字典类型是无序集合,可以以特定顺序排序遍历字典的键或值print(airports.keys.sort())
SwiftControlFlow
Swift提供了类似C语言的流程控制结构,包括可以多次执行任务的for和while循环,基于特定条件选择执行不同代码分支的if、guard和switch语句,还有控制流程跳转到其他代码的break和continue语句。
除了传统的for循环,Swift中还增加了for-in循环更加方便的遍历容器。switch语句也远比C语言中更加强大,如case无需写break,case可以匹配区间、元组和特定类型描述。case语句中匹配的值可以由case体内部临时变量决定,也可以由where分句描述更复杂的匹配条件。
For循环
import Foundation// 传统for循环for var index = 0; index \< 3; ++index { print("index is \(index)")}// for-in循环for index in 1...5 { print("\(index) times 5 is \(index * 5)")}// 不需要知道区间内每一项的值,可以用下划线替代变量名let base = 3let power = 4var answer = 1for \_ in 1...power { answer *= base}print(answer)// for-in遍历数组let names = ["Anna", "Alex", "Brain", "Jack"]for name in names { print("Hello \(name)!")}// for-in遍历字典let numbersOfLegs = ["spider": 8, "ant": 6, "cat": 4]for (animalName, legCount) in numbersOfLegs { print("\(animalName)s have \(legCount) legs")}
While循环
官方文档中,While循环用一个简单的游戏来说明,点个赞。
游戏的规则如下:
- 游戏盘面爆款25个方格,游戏目标是达到或者超过第25个方格
- 每一轮,你通过掷骰子来确定你移动的步数,移动的路线如右图所示
- 如果在某轮结束,你移动到梯子的底部,可以顺着梯子爬上去
- 如果在某轮结束,你移动到蛇的头部,你会顺着蛇的身体滑下去
//盘面用数组board表示let finalSquare = 25var board = [Int](count: finalSquare + 1, repeatedValue: 0)//有蛇和梯子的位置输入前进和后退值,如3号位置的梯子会前进8,14号位置会后退10board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08//本例骰子树并未设置随机,直到玩家位置到25号位置或超过25号位置,游戏结束var square = 0var diceRoll = 0while square \< finalSquare { // 掷骰子 if ++diceRoll == 7 { diceRoll = 1 } // 根据点数移动 square += diceRoll if square < board.count { // 如果玩家还在棋盘上,顺着梯子爬上去或者顺着蛇滑下去 square += board[square] }}print("Game Over!")// repeat-while循环重写本例square = 0diceRoll = 0repeat { // 顺着梯子爬上去或者顺着蛇滑下去 square += board[square] // 掷骰子 if ++diceRoll == 7 { diceRoll = 1 } // 根据点数移动 square += diceRoll} while square \< finalSquareprint("Game Over!")
条件语句
// if语句用法,与C语言相同let temperatureInFahrenheit = 90if temperatureInFahrenheit \<= 32 { print("It‘s very cold. Consider wearing a scarf")} else if temperatureInFahrenheit \>= 86 { print("It‘s really warm. Don‘t forget to wear sunscreen")}// switch语句会尝试与若干个模式(pattern)进行匹配,匹配成功执行对应代码// 为了匹配特定的值,Swift提供了几种更复杂的匹配模式// case语句决定哪一条分支被执行,switch语句必须完备// 每一个case分支必须包含至少一条语句,case语句会自动breaklet someCharacter: Character = "e"switch someCharacter {case "a", "e", "i", "o", "u" : print("\(someCharacter) is a vowel")case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "y", "n", "p", "q", "r", "s", "t", "v", "v", "w", "x", "z": print("\(someCharacter) is a consonant")default: print("\(someCharacter) is not a vowel or a consonant")}// 区间匹配let approximateCount = 62let countedThings = "moons orbiting Saturn"var naturalCount: Stringswitch approximateCount {case 0: naturalCount = "no"case 1..\<5: naturalCount = "a few"case 5..\<12: naturalCount = "several"case 12..\<100: naturalCount = "dozens of"case 100..\<1000: naturalCount = "hundreds of"default: naturalCount = "many"}print("There are \(naturalCount) \(countedThings)")// 使用元组在同一个switch语句中测试多个值,元组中的元素可以是值,也可以是区间// 可以使用下划线来匹配所有值let somePoint = (1, 1)switch somePoint {case (0, 0): print("(0, 0) is at the origin")case (\_, 0): print("(\(somePoint.0), 0) is on the x-axis")case (0, \_): 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")}// case允许将任意匹配的值绑定在临时变量或常量上,在该case分支中可以引用该值let anotherPoint = (2, 1)switch anotherPoint {case (let x, 0): print("on the x-axis with x value of \(x)")case (0, let y): print("on the y-axis with y value of \(y)")case (let x, let y):// = case let(x, y): print("somewhere else at (\(x), \(y))")}// case分支可以使用where语句判断额外的条件let yetAnotherPoint = (1, -1)switch yetAnotherPoint {case let(x, y) where x == y: print("(\(x), \(y)) is on the line y=x")case let(x, y) where x == -y: print("(\(x), \(y)) is on the line y=-x")case let(x, y): print("(\(x), \(y)) is just some arbitrary point")}
Control Transfer Statements
// continue语句立刻停止本次循环,重新开始下一次循环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)// break语句会立刻结束整个控制流的执行let numberSymbol: Character = "三"var possibleIntegerValue: Int?switch numberSymbol {case "1", "一" : possibleIntegerValue = http://www.mamicode.com/1case "2", "二" : possibleIntegerValue = http://www.mamicode.com/2case "3", "三" : possibleIntegerValue = http://www.mamicode.com/3case "4", "四" : possibleIntegerValue = http://www.mamicode.com/4default: break}if let integerValue = http://www.mamicode.com/possibleIntegerValue {"hljs-string">"The integer value of \(numberSymbol) is \(integerValue)")} else { print("An integer value could not be found for \(numberSymbol)")}// Swift中的switch不会从一个case分支执行到别的分支。如果需要执行多个分支的代码,需要使用fallthroughlet integerToDescribe = 5var description = "The number \(integerToDescribe) is "switch integerToDescribe {case 2, 3, 5, 7, 11, 13, 17, 19: description += "a primer number, and also" fallthroughdefault: description += " an integer "}print(description)// 带标签的语句// 为了便于在嵌套控制流中,准确break或continue循环体和switch代码块// 重写蛇与梯子的游戏代码// 盘面用数组board表示let finalSquare = 25var board = [Int](count: finalSquare + 1, repeatedValue: 0)// 有蛇和梯子的位置输入前进和后退值,如3号位置的梯子会前进8,14号位置会后退10board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08// 本例骰子树并未设置随机,直到玩家位置到25号位置或超过25号位置,游戏结束var square = 0var diceRoll = 0// 这个版本的游戏使用while循环体和switch代码块来实现,while循环体又一个标签名gameLoopgameLoop: while square != finalSquare { if ++diceRoll == 7 { diceRoll = 1 } switch square + diceRoll { case finalSquare: break gameLoop case let newSqure where newSqure > finalSquare: continue gameLoop default: square += diceRoll square += board[square] }}print("Game Over!")// guard不同于if语句,一个guard语句总有一个else分句func greet(person: [String: String]) { guard let name = person["name"] else { return } print("Hello \(name)!") guard let location = person["location"] else { return } print("I hope the weather is nice in \(location)")}greet(["name": "John"])greet(["name": "Jane", "location": "Cupertino"])
SwiftFunction
Swift函数语法灵活,既支持没有参数名字的C风格函数,也支持带外部参数的OC风格函数。函数可以接受不确定数量的传入参数,支持传入传出参数。函数类型可以像其他类型一般使用,可以作为函数形参,也可以作为函数返回类型。函数定义可以写在其他函数定义中,在嵌套函数中实现封装。
import Foundation// 使用元组作为函数返回func minMax\_(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 } else if value > currentMax { currentMax = value } } return (currentMin, currentMax)}let bounds = minMax\_([8, -6, 2, 109, 3, 71])print("min is \(bounds.0) and max is \(bounds.max)")// 可选元组返回类型,返回的元组可能没有值func minMax(array: [Int]) -\>(min: Int, max: Int)? { if array.isEmpty { return nil } var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } else if value > currentMax { currentMax = value } } return (currentMin, currentMax)}if let bounds = minMax([8, -6, 2, 109, 3, 71]) { print("min is \(bounds.0) and max is \(bounds.max)")}// 参数名称。函数参数有一个内部参数名和一个外部参数名// 外部参数名标记传递来函数调用的参数,本地参数名在实现函数的时候使用// 本地参数名前指定外部参数名,中间以空格分隔// 如不指定外部参数名,系统会将内部参数名作为外部参数名,第一个参数除外,第一个参数默认忽略外部参数名// 忽略外部参数名可以通过下划线\_代替外部参数名func someFunction(firstParameterName: Int, \_ secondParameterName: Int) { //}someFunction(1, 2)// 带有默认值的参数放在函数参数列表的最后。// 可变参数// 在变量类型名后面加...的方式定义一个可变参数,接受零个或多个值// 可变参数的传入值在函数体内为此类型的一个数组// 最多可以有一个可变参数,并且可变参数一般置于最后func arithmericMean(numbers: Double...) -\>Double { var total: Double = 0 for number in numbers { total += number } return total / Double(numbers.count)}print(arithmericMean(1, 2, 3, 4, 5))print(arithmericMean(3, 8.25, 18.75))// 函数参数默认是常量,试图在函数体内更改参数值将会导致编译错误。// 通过在参数名前面加关键字var来定义变量参数// 变量参数仅仅存在于函数调用的生命周期func alignRight (var string: String, totallLength: Int, pad: Character)-\>String { let amountToPad = totallLength - string.characters.count if amountToPad < 1 { return string } let padString = String(pad) for _ in 1...amountToPad { string = padString + string } return string}let originalString = "hello"let paddedString = alignRight(originalString, totallLength: 10, pad: "-")print(paddedString)// 如果想要一个函数可以修改参数的值,并且这些修改在函数调用结束之后仍然存在,需要设置为输入输出参数// 在参数名前面加关键字inout来定义输入输出参数// 当传入的参数作为输入输出参数时,需要在参数前加&符号,表示这个值可以被函数修改// 用inout标记的参数不能再被var或者let标记func swapTwoInts (inout a: Int, inout b: Int) { let temp = a a = b b = temp}var someInt = 3var anotherInt = 107print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")swapTwoInts(&someInt, b: &anotherInt)print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")// 函数类型由参数类型和返回类型组成// 没有参数并返回void类型的函数的函数类型是:()-\>void// 下面函数的函数类型:(Int, Int)-\>Intfunc addTwoInts(a: Int, \_ b: Int)-\>Int { return a + b}func mutiplyTwoInts(a: Int, \_ b: Int)-\>Int { return a * b}// 可以像使用其他类型一样使用函数类型var mathFunction: (Int, Int)-\>Int = addTwoIntsprint(mathFunction(2, 3))mathFunction = mutiplyTwoIntsprint(mathFunction(2, 3))// 变量类型同样可以推断let anotherMathFunction = mutiplyTwoIntsprint(mathFunction(3, 3))// 函数类型可以作为参数类型func printMathResult(mathFunction: (Int, Int)-\>Int, \_ a: Int, \_ b: Int) { print(mathFunction(a, b))}printMathResult(addTwoInts, 2, 4)// 函数作为返回类型func choseMathFunction(mathtype: String)-\>((Int, Int)-\>Int)? { switch mathtype { case "add" : return addTwoInts case "mutiply" : return mutiplyTwoInts default: return nil }}if let function = choseMathFunction("add") { print(function(3, 5))}// 嵌套函数// 嵌套函数对外界不可见,但是可以被封闭它的函数来调用。一个封闭函数也可以返回某个嵌套函数,使得这个函数可以再其他域中被使用func choseMathFunction2(mathtype: String)-\>((Int, Int)-\>Int)? { func divideTwoInts(a: Int, _ b: Int)->Int { return a / b } switch mathtype { case "add" : return addTwoInts case "mutiply" : return mutiplyTwoInts case "divide" : return divideTwoInts default: return nil }}if let function = choseMathFunction2("divide") { print(function(6, 3))}
SwiftClosure
闭包部分主要介绍了Swift中闭包表达式的基本语法,闭包的值捕获、非逃逸闭包@noescape
和自动闭包@autoclosure
值得注意一下,这些都是不太容易理解的地方。
import Foundation// 闭包是函数代码块// 闭包可以捕获或存储其所在上下文中任一常量和变量的引用,闭合并包裹// 全局函数是一个有名字但不回捕获任何值的闭包// 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包// 闭包表达式是一个利用轻量语法所写的可以捕获上下文中变量或常量的匿名闭包// sort()方法需要传入两个参数// 一个参数是数组,另外一个参数是一个闭包,负责排序判定,类型为:(String, String)-\>Boollet names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]// 闭包函数方式func backwards(s1: String, s2: String)-\>Bool { return s1 > s2}var reversed1 = names.sort(backwards)print(names, names.sort(), reversed1)// 闭包表达式方式let reversed2 = names.sort({(s1: String, s2: String)-\>Bool in return s1 \> s2})print(reversed2)// 根据上下文推断类型// 参数类型由names数组元素推断,返回类型由返回值推断// 大部分使用闭包作为函数参数的情况都可以推断闭包的参数和返回类型let reversed3 = names.sort({s1, s2 in return s1 \> s2})print(reversed3)// 单行表达式闭包可以隐藏return语句let reversed4 = names.sort({s1, s2 in s1 \> s2})print(reversed4)// 参数名称缩写let reversed5 = names.sort({$0 \> $1})print(reversed5)// 运算符函数,前提是排序元素(String)实现了运算符\>let reversed6 = names.sort(\>)print(reversed6)// 尾随闭包// 如果需要将一个很长的闭包表达式作为最后一个参数传递给函数时,可采用尾随闭包增加函数可读性let reversed7 = names.sort(){$0 \> $1}print(reversed7)// 例子: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}print(strings)// 闭包可以在其定义的上下文捕获常量或变量// 最简单的闭包形式是嵌套函数,嵌套函数可以捕获其外部函数所有的参数以及定义的常量或变量// 系统会拷贝捕获的参数,即便在原函数域外也可以使用,参数属于闭包// 闭包的传递是引用类型,对应唯一的一份闭包func makeIncrementor(forIncrement amount: Int) -\> ()-\>Int { var runningTotal = 0 func incrementor() ->Int { runningTotal += amount return runningTotal } return incrementor}let incrementByTen = makeIncrementor(forIncrement: 10)print(incrementByTen())print(incrementByTen())let incrementBySeven = makeIncrementor(forIncrement: 7)print(incrementBySeven())print(incrementByTen())let alsoIncrementByTen = incrementByTenprint(alsoIncrementByTen())// 非逃逸闭包,只在函数体内执行,函数返回之后不执行// 闭包作为函数的参数,用@noescape标记表示该闭包为非逃逸闭包var Header: ()-\>Voidfunc someFunctionWithNoEscape(@noescape closure: ()-\>Void)-\>()-\>Void { closure() // Header = closure 由于标记为非逃逸,不允许将闭包传出 // return closure return {print("a closure")}}// 闭包能实现懒求值,直到闭包调用时才执行操作// 采用自动闭包的函数调用时,函数参数可以接受一个闭包返回类型的语句,相当于省略{}// @autoclosure 特性暗含了 @noescape 特性var string = "Hello"var closureContainer: ()-\>String = {"World"}func someFunctionWithClosure(closure: ()-\>String) { print(closure())}someFunctionWithClosure(){string}func someFunctionWithAutoClosure(@autoclosure closure: ()-\>String) { print(closure()) // closureContainer = closure 标记为自动闭包,不允许将闭包传出}someFunctionWithAutoClosure(string)// 需要逃逸的自动闭包可以使用@autoclosure(escaping)func anotherFunctionWithAutoClosure(@autoclosure(escaping) closure: ()-\>String) { print(closure()) closureContainer = closure // 允许闭包逃逸}print(closureContainer())anotherFunctionWithAutoClosure(string)print(closureContainer()) // 闭包逃逸,在函数体外执行
原文链接:http://www.jianshu.com/p/0ce84d2a6fc6
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
Swift常用语法示例代码(一)