这是我对 Swift 3.0 整理的笔记,主要内容来自于官方文档,添加了一些指针的内容在最后。该笔记由于只是我个人用于学习整理以及回顾使用,所以没有对单项技术做太过深入的解析。如果你需要完整清晰的知识点解析,请看官方文档。那是最好的 The Swift Programming Language (Swift 3)
Swift 基础类型以及集合类型都是值类型。
Swift 带有类型推断功能,属性的类型可以注明,也可以通过初始值推断。
public func print(_ items: Any..., separator: String = default, terminator: String = default)
// 单行注释内容
/// 带 Xcode 代码提示的单行注释内容
/*
多行注释内容
*/
/**
带 Xcode 代码提示的多行注释内容
*/
Swift 不强制要求使用分号,但是也可以使用,比如在同一行内些多条独立语句的时候。
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
let paddedDouble = 000123.456 // 123.456
let oneMillion = 1_000_000 // 1000000
let justOverOneMillion = 1_000_000.000_000_1 // 1000000.0000001
// typealias <New Type Name> = Type Name>
typealias AudioSample = UInt16
把多个值组合成为一个复合值,元组内部的值可以是任意类型,不要求是相同类型。
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 输出 "The status code is 404"
print("The status message is \(statusMessage)")
// 输出 "The status message is Not Found"
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 输出 "The status code is 404"
print("The status code is \(http404Error.0)")
// 输出 "The status code is 404"
print("The status message is \(http404Error.1)")
// 输出 "The status message is Not Found"
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// 输出 "The status code is 200"
print("The status message is \(http200Status.description)")
// 输出 "The status message is OK"
使用 ? 和 ! 来表示可选类型。? 表示使用的时候可能为 nil, ! 表示使用的时候自动解包。
// 定义可能报错的函数
func canThrowAnError() throws {
}
// 调用该函数
do {
try canThrowAnError()
// 没有错误抛出
} catch {
// 有错误抛出
}
// 当 condition 为 true 则不会触发断言,否则就触发。
public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line)
// 位运算符
// 按位反运算 ( 0 1 交换 )
let bits: UInt8 = 0b00001111
~bits // 0b11110000
// 按位与运算 ( 都是 1 才为 1 )
let bitsA: UInt8 = 0b11111100
let bitsB: UInt8 = 0b00111111
bitsA & bitsB // 0b00111100
// 按位或运算 ( 有一个 1 则为 1)
let bitsA: UInt8 = 0b10110010
let bitsB: UInt8 = 0b01011110
bitsA | bitsB // 0b11111110
// 按位异或运算符 ( 只有 1 个是 1 时为 1 )
let bitsA: UInt8 = 0b00010100
let bitsB: UInt8 = 0b00000101
bitsA ^ bitsB // 0b00010001
// 按位左移、右移运算符
let bits: UInt8 = 4 // 00000100
bits << 1 // 00001000
bits << 2 // 00010000
bits << 5 // 10000000
bits << 6 // 00000000
bits >> 2 // 00000001
// 自定义运算符以及运算符函数
<prefix / infix / postfix> operator <运算符>: <优先级,或为空则默认级别>
static func <运算符>(left: <Type>, right: <Type>) -> <Type> {
...
}
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
infix operator +-: AdditionPrecedence
extension Vector2D {
static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
字符串是 struct 类型
// 字符
let : Character = "!"
// 初始化
var : String = String()
var : String = "Some String \() Other String"
// 字符串常用操作
/*
* 运算符 ( +, += )
* 函数操作 ( append(), insert(), remove(), removeSubrange() )
* 获取字符及字符数量 ( String.characters, String.characters.count )
*/
// Unicode
/*
* 转义字符
* \0(空字符) \\(反斜线) \t(水平制表符)
* \n(换行符) \r(回车符) \"(双引号) \'(单引号)
* Unicode 标量
* \u{任意一到八位十六进制数且可用的 Unicode 位码}
*/
// String.Index 字符串索引
let test = "This is a long String, and is end!"
^ ^
test.startIndex test.endIndex
// * 利用下标访问字符串
test[test.startIndex] // T
test[test.index(before: test.endIndex)] // !
test[test.index(after: test.startIndex)] // h
test[test.index(test.index, offsetBy: 5)] // s
test[test.endIndex] // 错误
test.index(after: test.endIndex) // 错误
test[test.startIndex ..< test.index(test.startIndex, offsetBy: 6)] // This i
// * 遍历下标
for index in test.characters.indices {
print(test[index])
}
// This is a long String, and is end!
Swift 中集合类型都是泛型
集合类型的数据类型必须明确
// 创建
var : [] = [Type](repeating: value>, count: )
// 访问
[]
[]
// 常用操作
/*
* 运算符 ( +, += )
* 常用属性 ( count, isEmpty )
* 常用方法 ( append(), insert(), remove(), removeAll(), removeLast(), removeFirst() )
*/
// 遍历
for value in array {
/* do some thing */
}
for (index, value) in array.enumerate() {
/* do some thing */
}
集合类型必须遵守 Hashable 协议
// 创建
var : Set<> = Set<>()
// 常用操作
/*
* 常用属性 ( count, isEmpty )
* 常用方法 ( insert(), remove(), removeAll(), removeFirst(), contains() )
*/
// 遍历
for value in set {
/* do some thing */
}
for (index, value) in set.sorted() {
/* do some thing */
}
// 集合操作
var a: Set = [1,2,3,4,5]
var b: Set = [3,4,5,6,7]
a.intersection(b) // [3,4,5] 相交元素
a.symmetricDifference(b) // [1,2,6,7] 非相交元素
a.union(b) // [1,2,3,4,5,6,7] 所有元素
a.subtracting(b) // [1,2] a 中的非相交元素
// 集合运算
* == // 是否完全一致
* a.isSubset(of: b) // a 中的元素 b 是否都有
* a.isSuperset(of: b) // b 中的元素 a 是否都有
* a.isStrictSubset(of: b) // a 中的元素 b 是否都有,并且 a != b
* a.isStrictSuperset(of: b) // b 中的元素 a 是否都有,并且 a != b
* a.isDisjoint(with: b) // a b 是否没有交集
// 创建
var : Dictionary<, <value type>> = Dictionary<, <value type>>()
// 访问和修改
[] = ? // 如果 Any 不为空则是新增或修改 key 值,否则就是删除 key 值。
// 常用操作
/*
* 常用属性 ( count, isEmpty )
* 常用方法 ( updateValue(), remove(), removeValue(), removeAll(), contains() )
*/
// 遍历
for (key, value) in dic {
/* do some thing */
}
for key in dic.keys.sorted() {
/* do some thing */
}
for value in dic.values.sorted() {
/* do some thing */
}
// for-in
for <value or _> in 0 ..< 10, or [1,2,3]> {
/* do some thing */
}
// while
while <条件> {
/* do some thing */
}
repeat {
} while <条件>
// if
if <条件> {
/* do some thing */
} else if <条件> {
/* do some thing */
} else {
/* do some thing */
}
// switch
switch <值> {
case <条件>:
/* do some thing */
case <条件>:
/* do some thing */
default:
/* do some thing */
}
// 各种示例
let value: Int = 10
switch value {
case 0: // 单一匹配
/* do some thing */
case 1, 2, 3: // 复合匹配
/* do some thing */
case 4 ..< 7: // 区间匹配
/* do some thing */
default:
/* do some thing */
}
let tuple: (Int, Int) = (10, 10)
switch tuple {
case (0, 0): // 单一匹配
/* do some thing */
case (1, 1), (2, 2): // 复合匹配
/* do some thing */
case (3 ..< 5, 4 ..< 6): // 区间匹配
/* do some thing */
case (_, 7), (8, _): // _ 匹配所有值,表示忽略
/* do some thing */
case (let x, 9): // 忽略并获取 $0 值
/* do some thing */
case let (x, y): // 忽略并获取 $0, $1 值
/* do some thing */
case let (x, y) where x == 7: // 使用 where 添加限定条件
/* do some thing */
default:
/* do some thing */
}
// guard
guard <条件> else {
<必须有 retrun, continue 等退出条件>
}
// 解包
guard let <value> = <value>? else {
<必须有 retrun, continue 等退出条件>
}
// continue 跳过当前循环中的后面部分,直接进入下一次循环
// break 跳出当前的循环
// return 退出当前的函数
// fallthrough switch 语句中使用,让某个 case 可以进入下一个 case.
// throw 错误抛出
// 循环标签
: while <条件> {
/* do some thing */
: while <条件> {
/* do some thing */
break name // 直接退出 name 循环
}
}
// Api 检查
if #available( , <...>, *) {
// statements to execute if the APIs are available
} else {
// fallback statements to execute if the APIs are unavailable
}
if #available(iOS 10, macOS 10.12, *) {
/* iOS 使用 iOS 10 的 API, macOS 使用 macOS 10.12 的 API */
} else {
/* 其他版本的 Api */
}
函数定义: func (<参数外部名> <参数内部名>: <参数类型> = <默认值> <可变参数 …>) -> <返回值类型>
函数类型: (<参数类型>…) -> <返回值参数>
嵌套函数: 函数中可以定义函数,该函数只有在函数内部有效。
闭包是自包含的代码库,可以在代码中被传递和使用。闭包可以捕获和存储其所在上下文中任意的常量和变量来使用,所以会导致引用计数 +1 从而有循环引用的风险。
全局函数是一个有名字但不会捕获任何值的闭包。嵌套函数是有名字并可以捕获函数内值的闭包。闭包表达式一般都是匿名闭包。
单表达式的闭包可以省略 retrun 关键字。
闭包内的参数在未定义的情况下可以使用 $0 来对参数名称进行缩写,$0 表示第一个参数, $1 表示第二个参数,以此类推。
闭包是引用类型的值。
@noescape 表示非逃逸闭包,限定了闭包的生命周期只能存在于当前函数当中。
@autoclosure 表示自动闭包,这种闭包不接受参数,并且由返回值。用于传递作为参数的表达式,并可以省略花括号。自动闭包都默认带了 noescape 属性,如果想要声明为可逃逸闭包则是 @autoclosure(escaping).
{ (<参数名>: <参数类型>) -> <返回值类型> in
<闭包实现>
}
闭包在使用的时候可以有几种不同的方式,以 sorted 调用为例:
// 完整
closures.sort(by: { (v0: Int, v1: Int) -> Bool in
return v0 > v1
})
// 上下文推断
closures.sort(by: { v0, v1 in
return v0 > v1
})
// 隐式返回值
closures.sort(by: { $0 > $1 })
// 运算符函数返回
closures.sort(by: >)
// 尾闭包
closures.sort { $0 > $1 }
// 非逃逸闭包
func name(@noescape closures: (Int) -> Bool) {
if closures(10) {
return
}
}
// 自动闭包
func name(@autoclosure(escaping) closures: () -> String) {
customerProviders.append(closures)
}
if let <value> = <object>.<value>?.<function>?.[] ?.<array>[] {
/* 只要其中有 1 个 nil, 就会返回 nil, 否则会逐层解压。*/
/* 利用可选链的特性,可以实现链式编程。 */
}
// 普通枚举
enum <name> {
case <case>
case <case>
...
}
enum <name> {
case <value>, <value> ...
}
enum Type {
case a
case b
}
var type: Type = Type.a
// 关联值
enum <name> {
case <case>(<type>, <type>...)
case <case>(<type or other type> ...)
}
enum Type {
case a(Int)
case b(String)
case c(Int, Double)
}
var type: Type = Type.a(10)
var type: Type = Type.b("Test")
var type: Type = Type.c(10, 5.0)
// 原始值
enum <name>: <type> {
case <case> = <value>
case <case> = <value>
...
}
enum <name>: <type> {
case <case> = <value>, <case>, <case> = <value>, <case>...
}
enum Type: Int {
case a = 1, b, c, d = 10, e, f
}
var type: Type = Type.b // rawValue = 2; Type.e.rawValue = 11
var type: Type? = Type(rawValue: 12) // Type.f
// 递归枚举
// 部分可使用递归
enum <name> {
case <case>(<type>)
indirect case <case>(<name>)
}
// 全部可使用递归
indirect enum <name> {
case <case>(<type>)
case <case>(<name>)
}
indirect enum Type {
case a(Int)
case b(Type)
}
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
// return ((5) + (4)) * (2)
// 18
扩展
类与结构体的差异:
可以使用 (===) 以及 (!==) 判断两个类是否是同一个对象。
class : , {
/** 属性 **/
var : = // 存储属性
lazy var : = // 延迟属性
static var : = // 类型属性,静态属性
let : = { // 通过闭包对值进行初始化, let var 都行
return
}()
var : { // 计算属性,不存储内容
get {
/* 只读属性可以不写 get {}, 直接 return */
return
}
set(newValue) {
/* set 属性可以不设置,则是只读属性 */
}
}
var : = { // 添加属性观察器
didSet {
/* ... */
}
willSet {
/* ... */
}
}
/** 方法 **/
func (...) { // 实例方法
}
override func (...) { // 重写方法
}
class func (...) { // 类方法
}
/** 下标 **/
subscript(...) -> {
get {
return
}
set(newValue) {
/* ... */
}
}
/** 构造器和析构器**/
init(...) {
// super.init(...)
}
convenience init(...) {
/* ... */
self.init(...)
}
deinit {
}
}
struct : {
/** 属性 **/
var : = // 存储属性
lazy var : = // 延迟属性
var : { // 计算属性,不存储内容
get {
/* 只读属性可以不写 get {}, 直接 return */
return
}
set(newValue) {
/* set 属性可以不设置,则是只读属性 */
}
}
var : = { // 添加属性观察器
didSet {
/* ... */
}
willSet {
/* ... */
}
}
static var : = // 类型属性,静态属性
/** 方法 **/
func (...) {
}
mutating func (...) {
}
static func (...) {
}
/** 下标 **/
subscript(...) -> {
get {
return
}
set(newValue) {
/* ... */
}
}
/** 构造器 **/
init(...) {
// super.init(...)
}
}
subscript(: …) ->
required init() 必要构造器,子类必须要重写构造器
构造器规则
两段式构造过程中构造流程展示:
析构器会在实例释放发生之前被自动调用。
class / struct / enum 类型中都可以再定义新的类型。
Struct A {
enum B {
case ab
enum C {
case abc
}
}
}
let abc = A.B.C.abc
// 使用
extension {
...
}
var : (...) -> <return type> = {
[unowned , weak = self.value] (: ...) -> <return type> in
...
return ...
}
lazy var closure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
return ...
}
// 使用准守 Error 协议的枚举来表示错误
enum : Error {
case <case>
}
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
// 在发生错误的地方抛出错误抛出错误
throw
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
// 使用 throws 表示一个函数可能会抛出错误
func (...) throws ->
// do-catch 处理错误
do {
try
<无错误>
} catch case> {
<错误处理>
} catch case> where <错误限定条件> {
<错误处理>
} catch {
<不被前面条件捕获的错误处理>
}
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}
// try? 处理,如果错误返回 nil
let <value> = try?
// try! 处理,禁用错误传递,如果错误就崩溃
let <value> = try!
// defer
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}
// 定义,以下包含协议可以定义的内容
protocol {
var : { get set } // 定义属性
func (...) -> // 定义方法
static func (...) -> // 定义静态方法
mutating func (...) -> // 定义 mutating 方法
init(...) // 定义构造器
subscript(_: ) -> { get set } // 下标
}
// 遵循某协议
class : {
/* 实现协议所规定的内容 */
}
// 将协议作为类型
func (: ) -> {
...
}
// 通过扩展实现协议
extension : {
/* 实现协议所规定的内容 */
}
// 继承
protocol : , ... {
/* 定义 */
}
// 合成
func (: protocol<, >) -> {
...
}
// 一致性
if is { }
if let = as? { }
// 可选协议及参数
@objc protocol {
@objc optional func (forCount count: Int) -> Int
@objc optional var : Int { get }
}
if let = .?(...) { }
// 协议扩展
extension {
/* 不能扩展存储属性,而且必须提供默认实现 */
}
// 限制条件
extension where <限定条件> {
/* 不能扩展存储属性,而且必须提供默认实现,只有符合限定条件的对象才会有该内容。 */
}
// 关联类型
protocol {
associatedtype
/* ... use Type name */
}
class/struct : {
typealias =
/* 使用 typealias 指定 Type name 为具体类型 */
}
class/struct : {
/* Generics 可以就是 Type Name */
}
/* Generics 表示泛型类型,不加 <> 号,因为泛型需要被 <> 包含 */
// 泛型函数
func (...) -> {
...
}
func genericsFunc<T>(input: T) -> T {
...
}
// 泛型类型
class/struct {
}
class Stack<T> {
var item = [T]()
}
let s = Stack()
// 泛型约束
func >(...) {
...
}
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
// 关联类型
protocol {
associatedtype
/* ... use Type name */
}
class/struct : {
typealias =
/* 使用 typealias 指定 Type name 为具体类型 */
}
class/struct : {
/* Generics 可以就是 Type Name */
}
protocol Test {
associatedtype Item
func append(item: Item)
}
struct TestStruct: Test {
typealias Item = Int
func append(item: Item) { ... }
}
class Stack<T>: Test {
var item = [T]()
func append(item: T) { ... }
}
let test = TestStruct()
let stack = Stack()
// Where 子句
func test(a: A, b: B) -> Bool where A.Item == B.Item, A.Item: Equatable {
/*
test 函数有两个泛型 A, B
A 遵守 Test 协议,B 遵守 Test 协议(可以是不同的协议)
并且 (where)
A 的 Item 类型 必须等于 B 的 Item 类型 (比如都是 Int?)
并且 (,)
A 的 Item 类型遵守 Equatable 协议
*/
}
注意:当你使用指针指向某个变量的时候,ARC 环境下并不会给这个变量添加引用计数,所以有可能会在你调用之前就把该变量释放,这时候再使用指针将会出现不可预知的结果。
// 申请内存空间并初始化一个指针
let <name> = UnsafeMutablePointer<Type>.allocate(capacity: Int)
// 申请内存空间
<Pointer>.initialize(to: <value>) // 初始化内存空间
<Pointer>.pointee // 通过 pointee 变量可以访问指针的内容,就好像 *pointer
<Pointer>.deallocate(capacity: Int) // 释放内存空间
let pointer = UnsafeMutablePointer<String>.allocate(capacity: 1)
pointer.initialize(to: "Test")
pointer.pointee // "Test"
pointer.deallocate(capacity:1)
// 通过参数传递获取指针
func method(name: UnsafePointer<Type>) { }
method(name: &value) // 使用 & 在传递参数的时候传递 value 的指针
// 通过 withUnsafeMutablePointer 直接访问变量的指针
func withUnsafeMutablePointer<T, Result>(to arg: inout T, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
var value: String = "Test"
withUnsafeMutablePointer(to: &value) { $0.pointee += "OK" }
print(value) // TestOK
// 通过 withMemoryRebound 函数对指针的类型进行转换
func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
var addr = sockaddr()
withUnsafeMutablePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
$0.pointee.sin_addr.s_addr = inet_addr("127.0.0.1")
}
}
// 通过 UnsafeRawPointer 来获取一个 void* 指针并转换成其他类型的指针
let intP = UnsafeMutablePointer<Int>.allocate(capacity: 1)
intP.initialize(to: 200)
let voidP = UnsafeRawPointer(intP)
let int32P = voidP.assumingMemoryBound(to: Int32.self)
int32P.pointee // 200
// 通过 advanced 函数来对指针进行移动
var p = UnsafeMutablePointer<Int>.allocate(capacity: 5)
for i in 0 ..< 5 {
p.advanced(by: i).pointee = i + 10
}
for i in 0 ..< 5 {
print(p.advanced(by: i).pointee) // 10, 11, 12, 13, 14
}
p.deallocate(capacity: 5)
* 需要注意的是,如果这里把循环的次数改成 5 以上的数字也不会崩溃。而且可以正常的进行赋值操作。但是就好像 C 中的指针一样,你不会知道这到底会有什么影响。
// 使用 UnsafeBufferPointer 指针数组
// 使用上一个例子中的 p 指针
var ap = UnsafeBufferPointer(start: p, count: 5)
ap.forEach {
print($0) // 10, 11, 12, 13, 14
}
// 数组类型本身也有方法访问 UnsafeBufferPointer
var a = [20,21,22,23,24]
a.withUnsafeBufferPointer {
$0.forEach {
print($0) // 20, 21, 22, 23, 24
}
}
// 事实上,可以直接把数组当成 UnsafePointer 进行传递
func method(p: UnsafePointer) {
print(p.pointee)
}
method(p: a) // 20