Swift 语法概览(一)

1. 基础

常量 && 变量

// 常量
let age = 20
// 变量
var weight = 120.4

// 类型标识
var welcomeMessage: String
welcomeMessage = "Hello"

// 统一类型
var red, green, blue: Double

整数

Int:在32位平台上是Int32,在64位平台上是Int64
UInt:在32位平台上是UInt32,在64位平台上是UInt64
其他整数:Int8,Int16,Int32,Int64
整数范围

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

浮点数

Float:32位浮点数
Double:64位浮点数

类型安全和类型推导

Swift 是类型安全语言,在编译期间执行类型检查来避免类型错误,但这并不意味着定义变量都要指定类型,Swift 提供类型推导机制,比如:

// Int 类型
var age = 20
// Double 类型
var weight = 120.5
// Double 类型
var height = 170 + 1.5

不同类型之间的数字运算需要做显式转换,隐式转换不被允许的:

let three = 3
let pointOneFourOneFiveNine = 0.14159
// 不加Double() 转换,报错
let pi = Double(three) + pointOneFourOneFiveNine

类型别名

typealias AudioSample = UInt16

var maxAmplitudeFound = AudioSample.min

布尔类型

let turnOn = true

if turnOn {
    print("turnOn is true")
} else {
    print("turnOn is false")
}

由于类型安全,Swift 中非布尔类型不能代替布尔类型使用,比如代码报错:

// 编译报错
if 1 {
  print("1 不能代替 true")
}

元组

元组是一组数据的集合,可以是不同的数据类型

// 定义一个元组,类型:(Int,  String)
let http404Error = (404, "Not Found")

// 获取数据
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
// 获取部分数据
let (justTheStatusCode, _) = http404Error

// 索引访问
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")

// 定义时提供别名
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")

Optional(可选变量)

optional 修饰的变量代表该变量可能有值,也可能没值。没值通过 nil 来表示

不能将非可选变量的值设置为nil

var serverResponseCode: Int? = 404
serverResponseCode = nil

// 无初始化值默认为 nil
var surveyAnswer: String?

Swift 中的 nil 和 OC 中的 nil 不一样,OC 中的 nil 代表是 空对象指针,用在对象类型上,Swift 的 nil 表示某个变量没有值,所有类型都可以使用。

可选值的解包

强制解包
当确认某个变量一定有值的时候,可以使用强制解包符号 !

var convertedNumber: Int? = 404
if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

可选绑定
if,while 条件语句可以使用可选绑定来解包

var convertedNumber: Int? = 404
if let actualNumber = convertedNumber {
    print("The convertedNumber has an integer value of \(actualNumber)")
} else {
    print("The convertedNumber has no value")
}

// 多个解包操作,有一个返回 nil 则 if 语句条件判断失败
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}

隐式解包
什么玩意?

let possibleString: String? = "An optional string."
// 需要解包使用
let forcedString: String = possibleString! 

let assumedString: String! = "An implicitly unwrapped optional string."
// 不需要解包,根据类型推导,这里会自动强制解包
let implicitString: String = assumedString

// 不自动解包,optionalString 是 optional 类型
let optionalString = assumedString

错误处理

func makeASandwich() throws {
    // this function may or may not throw an error
}

do {
    try makeASandwich()
    eatASandwich()
} catch SandwichError.outOfCleanDishes {
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
    buyGroceries(ingredients)
}

Assertions and Preconditions

断言,他们之间的区别是 Assertions 只在 Debug 环境下生效,Preconditions 在 Debug 和 Product 环境下都生效。

let age = -3
assert(age >= 0, "A person's age can't be less than zero.")

precondition(index > 0, "Index must be greater than zero.")

基本运算符

赋值运算符(=)没有返回值
默认算术运算符不允许值溢出

运算符特殊操作:

// 字符串连接
"hello, " + "world"  // equals "hello, world"

// 溢出操作符
let c = a &+ b

// 取余运算
a % b
a = (b x some multiplier) + remainder
-9 % 4   // equals -1
-9 = (4 x -2) + -1

// 三元
a != nil ? a! : b 等价于 a ?? b

// 区间运算符
// 闭区间 a...b
for index in 1...5 {
    print("\(index)")
    //打印 1 2 3 4 5
}
// 半开区间 a..

2. 字符和字符串

初始化操作

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // initializer syntax

if emptyString.isEmpty {
    print("Nothing to see here")
}

// 可变字符串
var variableString = "Horse"
variableString += " and carriage" // Horse and carriage
// 不可变字符串
let constantString = "Highlander"
constantString += " and another Highlander" // 编译报错

字符串字面量

// 单行
let someString = "Some string literal value"

// 多行
let quotation = """
The White Rabbit put on his spectacles.  "Where shall I begin,
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""

扩展字符

//  \n 不会换行
let str = #"Line 1\nLine 2"#

//  \n 会换行
let str = #"Line 1\#nLine 2"#

字符操作

for character in "Dog!" {
    print(character)
}
// D o g  ! 

let exclamationMark: Character = "!"
let catCharacters: [Character] = ["C", "a", "t", "!", ""]

字符串操作

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"

var instruction = "look over"
instruction += string2
// instruction now equals "look over there"

// 字符串插入
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"

print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."

字符计数

// 特殊例子
var word = "cafe"
print("the number of characters in \(word) is \(word.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.count)")
// Prints "the number of characters in café is 4"

字符访问

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

for index in greeting.indices {
    print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n   T a g ! "

插入 && 删除

var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"

welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"

welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"

let range = welcome.index(welcome.endIndex, offsetBy: -6)..

3. 集合类型

Swift 提供三种集合类型,Arrays,Sets,Dictionarys。

用 var 定义的集合就是可变集合

Arrays

Arrays 存储相同数据类型,元素有序,可重复

let a:[Any] = [1,2,"33"] 这个类型不一致是什么鬼?

var someInts = [Int]()
someInts.append(3)
someInts = []

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
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]

var shoppingList: [String] = ["Eggs", "Milk"]
// 类型推导
var shoppingList = ["Eggs", "Milk"]

if shoppingList.isEmpty {
    print("The shopping list is empty.")
} else {
    print("The shopping list is not empty.")
}

// 用 "Bananas", "Apples" 替换 [4-6]位置的元素
shoppingList[4...6] = ["Bananas", "Apples"]

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

let mapleSyrup = shoppingList.remove(at: 0)

// 遍历
for item in shoppingList {
    print(item)
}
for (index, value) in shoppingList.enumerated() {
    print("Item \(index + 1): \(value)")
}

Sets

Sets 存储相同数据类型,元素无序,不可重复,Sets 中的元素必须可以计算哈希值,本质上 Sets 是通过哈希表实现的。
Sets 定义类型关键字不能省略,因为表示语法和数组类似的

var letters = Set()
letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

// 插入
favoriteGenres.insert("Jazz")

// 删除
if let removedGenre = favoriteGenres.remove("Rock") {
    print("\(removedGenre)? I'm over it.")
} else {
    print("I never much cared for that.")
}
// Prints "Rock? I'm over it."

// 遍历
for genre in favoriteGenres {
    print("\(genre)")
}

// 集合操作(交集,并集等)
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]

Dictionaries

Dictionaries 存储 key-value 对

var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]

var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
airports["LHR"] = "London"

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}

if let airportName = airports["DUB"] {
    print("The name of the airport is \(airportName).")
} else {
    print("That airport is not in the airports dictionary.")
}

if let 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."

for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}

for airportCode in airports.keys {
    print("Airport code: \(airportCode)")
}
// Airport code: LHR
// Airport code: YYZ

for airportName in airports.values {
    print("Airport name: \(airportName)")
}
// Airport name: London Heathrow
// Airport name: Toronto Pearson

let airportCodes = [String](airports.keys)
// airportCodes is ["LHR", "YYZ"]

let airportNames = [String](airports.values)
// airportNames is ["London Heathrow", "Toronto Pearson"]

4. 控制流

For-In

for-in 可以用在序列上,比如 Arrays,Dictionarys,Sequence,Range等

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    print("Hello, \(name)!")
}

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}

for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
    // 5 10 15 20 25
}

var power = 10;
for _ in 1...5 { // 忽略 index 值
    power *= 2;
}

// 半开区间
let minutes = 60
for tickMark in 0..

While

var num = 10
while num > 0 {
    print("循环10次")
    num --;
}

repeat {
   print("循环10次")
    num --;
} while num > 0

条件语句

let temperatureInFahrenheit = 90
if 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.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}

Switch

在 Swift 中,switch 语法的 case 语句不会默认接着执行下一个case,不需要 break 来中断,在 switch 中使用 break 会导致退出整个 switch 的执行。要实现 C 语言中那种 case-by-case 的效果,需要使用 fallthrough 关键字。

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
    fallthrough
default:
    print("Not the letter A")
}
范围匹配
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
    naturalCount = "no"
case 1..<5:
    naturalCount = "a few"
case 5..<12:
    naturalCount = "several"
default:
    naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
Tuples 匹配
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
Value Bindings
let anotherPoint = (2, 0)
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)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"
Where
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// Prints "(1, -1) is on the line x == -y"

控制转移

continue,break,fallthrough 略

Labeled Statements
gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        continue gameLoop
    default:
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")
guard

和 if 类似,必须提供 else 分支,暂时不明用这玩意的必要性。

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }
    print("Hello \(name)!")
    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }
    print("I hope the weather is nice in \(location).")
}
API 可用检查
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
}

5.Functions

无返回值,无参数函数
func sayHelloWorld()  {
    print("hello, world")
}
单条语句隐式返回
func greeting(person: String) -> String {
    "Hello, " + person + "!"
}
带参数,返回值,-> 是返回箭头
func greet(_ person:String, from user: String, world: String = "Hello") -> String {
    return "to:\(person), greeting from:\(user), world:\(world)"
}
greet("Json", from:"End", world: "你好");
greet("Json", from:"End");

// 返回多个值
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1.. currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
可变参数
func arithmeticMean(_ 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
inout 参数

默认情况,函数中的参数都是只读,不能修改,要修改需要使用 inout 修饰

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

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"
函数类型
var mathFunction: (Int, Int) -> Int = addTwoInts

6. 闭包

语法
{ (parameters) -> return type in
    statements
}
几个排序用法
// 数组排序
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

// 根据上下文类型推导
// 因为是 String 类型的数组调用 sort 方法
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

// 单表达式隐式返回
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

// 参数速记,可省略参数列表和 in 语句
reversedNames = names.sorted(by: { $0 > $1 } )

// 运算符函数,String 类型有定义 > 运算符函数
reversedNames = names.sorted(by: >)
尾随闭包

当闭包作为函数最后一个参数时,可以写成尾随闭包

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体代码
}

// 正常方式调用
someFunctionThatTakesAClosure(closure: {
    // 闭包实现代码
})

// 尾随闭包调用
someFunctionThatTakesAClosure() {
    // 闭包实现代码
}

// 上面的排序可以修改成尾随闭包调用
reversedNames = names.sorted() { $0 > $1 }

// 如果尾随闭包是函数的唯一参数,() 也可以省略
reversedNames = names.sorted { $0 > $1 }
变量捕捉

runningTotal 之所以会变是因为函数和闭包是引用类型

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
逃避闭包

简单说就是一个闭包作为参数传入函数后,并不是在函数体内执行,而是在函数返回后才会在某个时机执行,比如异步请求,这时需要把这个闭包声明为逃逸闭包,之所以要明确是不是逃逸闭包,应该是为了内存优化管理

var completionHandlers = [() -> Void]()
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
Autoclosures
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// Prints "5"

print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"

你可能感兴趣的:(Swift 语法概览(一))