Swift总结

181 阅读3分钟

Swift基础

Playground

截屏2021-08-26 下午12.58.14.png

元组

`let http404Error = (404, "Not Found")

let (code, msg) = http404Error

let (onlyCode, _ ) = http404Error

let http200Status = (code: 404, description: "OK")`

流程控制

if

只支持 bool 类型

switch

区间匹配、元组匹配

// 区间匹配
let count = 2
switch count {
case 0:
    print("")
case 1...2:
    print("")
case 3..<7:
    print("")
case 7...:
    print("")
default:
    print("")
}

// 元组匹配
let point = (1, 1)
switch point {
case (0, 0):
    print("")
case (0...3, 0...3):
    print("")
case (_, 0):
    print("")
default:
    print("")
}

值绑定

// 值绑定
switch point {
case (let x, 0):
    print("\(x)")
case let (x, y):
    print("\(x)\(y)")
}

where子句

// where子句
switch point {
case (let x, 0):
    print("\(x)")
case let (x, y) where x == y:
    print("\(x)\(y)")
default:
    print("")
}

var numbers = [-10, 0, 1, 2]
for x in numbers where x > 0 {
}

方法

// 标准函数定义
func a(i: Int, j: Int) -> (Int, Int) {
    return (i, j)
}

func a1(i: Int, j: Int) -> Int {
    return i + j
}

// 省略返回值
func a2(i: Int, j: Int) {

}

// 参数标签
func a3(i param1: Int, j param2: Int) -> Int {
    return param1 + param2
}

func a3(_ i: Int, _ j: Int) -> Int {
    return i + j
}

// 默认参数值
func a4(i: Int = 10, j: Int) {

}

// 可变参数
func a5(i: Int...) {
    for x in i {
        print("\(x)")
    }
}

inout

// inout
func swapValues(_ v1: inout Int, _ v2: inout Int) {
    let temp = v1
    v1 = v2
    v2 = temp
}
  1. 可变参数不能标记为 inout
  2. inout 参数不能有默认值
  3. inout 参数的本质是地址传递
  4. inout 参数只能传入可以被多次赋值的 我认为,本质上针对 inout 的限制原因都在第4条,其他只是引申出来的。

汇编小技巧:

  • lea 是传递地址:leaq xxx %yyy,值xxx 作为地址
  • %xxx 都是寄存器
  • (xxx) 表示作为地址:movq xxx (yyy),把xxx复制给地址为yyy的内存

函数重载

规则:

  • 函数名相同
  • 参数个数不同,或者参数类型不同,或者参数标签不同
  • 返回值是否相同不影响 我认为就是指编译器是否能准确识别出你要调用哪个函数

函数类型

// 函数类型
func a6() {} // ()->()或者()->Void

func a7(a: Int, b: Int) -> Int {
    return a
} // (Int, Int) -> Int

枚举

关联值vs.原始值

关联值:将枚举的成员值跟其他类型的数据关联存储在一起 原始值:枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做原始值

隐式原始值

如果枚举的原始值类型是Int、String,swift会自动分配原始值

递归枚举

枚举占用的空间大小

enum Password {
    case number(Int, Int, Int, Int)
    case other
}

MemoryLayout<Password>.side // 真实使用了33个字节,Int占8个字节,1个字节表明枚举成员类型,
MemoryLayout<Password>.aligmn // 8,对齐参数
MemoryLayout<Password>.stride // 40个字节,size是33,因为对齐参数是8,所以真实分配的存储空间大小是40个字节

可选项

1、可选项绑定

2、空合并运算符??

public func ?? <T>(optional:T?, defaultValue:@autoclosure ()->T?)->T?
public func ?? <T>(optional:T?, defaultValue:@autoclosure ()->T)->T

3、隐式解包

为什么会有隐式解包?

为了解决限制严格的初始化过程造成的不方便。如果成员变量被声明成T,那么在初始化完成前,它一定要被赋上值,否则只能声明为T?

但实际上有时候不想/不能在初始化时就赋值,但是可以肯定的是在使用前一定有值。

所以就有了隐式解包T!

结构体

编译器会根据情况,为结构体生成多个初始化器,宗旨是:保证所有成员都有初始值

struct Point {
    var x: Int = 10
    var y: Int
}

ok的:
var p1 = Point(x: 10, y: 10)
var p3 = Point(y: 10)

编译不能通过:
var p2 = Point(x: 10)
var p4 = Point()

struct Point {
    var x: Int?
    var y: Int?
}

都ok:
var p1 = Point(x: 10, y: 10)
var p3 = Point(y: 10)
var p2 = Point(x: 10)
var p4 = Point()

编译器没有为类自动生成可以传入成员值的初始化器