Swift 拾遗
基础语法
- 常量
let
和变量var
let name = "Sun"
var mutableName = "Li"
编译器会推断该变量类型.
也可以指定类型
let name: String = "Hello"
-
类型别名 typealias
typealias MyInt = Int
-
Bool 类型
在需要使用Bool 类型的地方使用了非Bool ,会触发错误
let i = 1
if i { ... } // 错误提示
//更改为
if i == 1 { ... }
- 元组
let http404 = (404,"notFound")
// 还可以给元素命名
let http404 = (status:404,msg:"notFound")
let (statusCode , statusMsg) = http404
//访问第二个元素
print(" \( http404.1)")
-
强制解析 !
-
可选绑定
if let constName = someOption { ... }
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100") } // 输出 "4 < 42 < 100"
if let firstNumber = Int("4") { if let secondNumber = Int("42") { if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100") } } } // 输出 "4 < 42 < 100"
- 隐式解析 !
当我们第一次声明一个变量的时候就可以确定他一定有值,那摩我们就可以使用非可选类型 (在类型后面使用 ! ,而非 ?),这样在使用的时候就不必 强制解析了
let possibleSting: String ! = "Sun"
运算符
- swift 提供恒等
===
和!==
来判断两个对象是否引用同一个实例对象 - Nil Coalescing Operator 空合 运算符 ??
a ?? b 对a 进行解包,如果包含值就 解包,否则就返回默认值 b。(表达式a 必须按时Optional 类型,且b的类型要和a 解包后的类型一致) - 区间运算符 a...b a..< b
字符串
是值类型,每次进行方法传递都会进行值的 copy
集合 Array,Set,Dictionary
使用var
,let
指定集合的可变和不可变
- Array
存储同一类
型的多个值,可以使用Array<Element>指定存储的元素类型
var someInt = [Int] ()
var someInt 2= [1,1,3]
var threedous = Array(repeating:20.0,count :3)
var shoopingList:[String] = ["a","b"]
//遍历
for item in shoppingList { }
for (index,value) in shoppingList.enumerated() {
print("\(index) = \(value)")
}
- 集合类型 Set
你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的 Hashable 协议。符合 Hashable 协议的类型需要提供一个类型为 Int 的可读属性 hashValue 。由类 型的 hashValue 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同
因为 Hashable 协议符合 Equatable 协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符( == )的实 现。这个 Equatable 协议要求任何符合 == 实现的实例间都是一种相等的关系。也就是说,对于 a,b,c 三个值来 说, == 的实现必须满足下面三种情况: • a == a (自反性) • a == b 意味着 b == a (对称性) • a == b && b == c 意味着 a == c (传递性)
集合的创建
var letters = Set<Character>()
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
字典
可以用 [Key: Value] 这样简化的形式去创建一个字典类型。
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
let emptyDic = [String:String] ()
let dic = Dictionary<String,Int>()
遍历
for (airportCode, airportName) in airports {
print("(airportCode): (airportName)")
}
for airportCode in airports.keys {
print("Airport code: (airportCode)")
} // Airport code: YYZ // Airport code: LHR
for airportName in airports.values {
print("Airport name: (airportName)")
}
控制流
switch
- 不存在隐式贯穿,即 匹配一个case 后就终止匹配,不会执行default
- switch 允许区间匹配
case (100... 400):
和默认值匹配(_,anthor)
- case 值绑定
case (let x ,let y) :
-
where
条件
case let (x,y) where x == y :
- 复合匹配
就是将多个符合条件情况放到一个case下,用,
分隔开
case (let a,0) ,(0,let b) :
- 每一个case 都必须有执行语句
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 无效,这个分支下面没有语句
case "A":
print("The letter A")
default:
print("Not the letter A")
} // 这段代码会报编译错误
改为
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
} // 输出 "The letter A
函数
- 可变参数
函数参数是同一类型的参数常量
func mutableParams(param: Double...) -> Double{
var total = 0.0;
for item in param {
print(item)
total += item
}
return total
}
- inout 参数
使用inout
修饰,使用&
传递参数引用
func swap(p1: inout Int, p2: inout Int) -> (Int,Int) {
let temp = p1
p1 = p2
p2 = temp
return (p1,p2)
}
- 函数类型
函数的类型是由 函数的参数和返回值确定的
我们定义一个函数类型的变量
var backCount: (Int ,Int) -> Int = swap
闭包
学习闭包和可能会被他那简略的语法迷惑,我们这里做一个总结
- 利用上下文推断参数类型和返回值类型
- 单表达式闭包可省略
return
- 参数名缩写
- 尾随闭包
- 闭包和函数都是引用类型
public mutating func sort(by areInIncreasingOrder: (Element, Element) -> Bool)
闭包语法
{ (params) -> in
exec...
}
-
参数省略
return
在单表达式中可以省略 ,它会根据上下文推断得出,有时候in
也可以省略 -
参数名缩写
$0
,$1
尾随闭包
如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾 随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你 不用写出它的参数标签
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用 someFunctionThatTakesAClosure(closure: {
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用 someFunctionThatTakesAClosure() {
// 闭包主体部分
}
逃逸闭包
- 在参数名之前加
@escaping
- 该闭包在函数返回之后执行
- 默认情况下是非逃逸的
将一个闭包标记为 逃逸意味着你必须在闭包中显式地引用 self 。比如说,在下面的代码中,传递到 omeFunctionWithEscapingClosure(:) 中的闭包是一个逃逸闭包,这意味着它需要显式地引用 self 。相对 的,传递到 someFunctionWithNonescapingClosure(:) 中的闭包是一个非逃逸闭包,这意味着它可以隐式引用 self
另外将一个闭包添加到函数之外的数组中,在函数定义的时候也需要明确指明盖闭包是逃逸的,不然编译错误
自动闭包
自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。 这种闭包不接受任何参数,当它被调 用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够省略闭包的花括号,用一个普通的表达式 来代替显式的闭包。
自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] print(customersInLine.count) // 打印出 "5"
let customerProvider = { customersInLine.remove(at: 0) } print(customersInLine.count) // 打印出 "5"
print("Now serving \(customerProvider())!") // Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出 "4"
我们举一个将闭包传递给函数的例子
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// 打印出 "Now serving Alex!"
如果我们不传递一个显示的闭包,而是传递一个自动闭包
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0)) // 打印 "Now serving Ewa!"
恩,有点😲,休息一下🙃