Fork me on GitHub

带你初识Swift4.0,踏入Swift的大门

背景

由于Swift4之前的版本也看过好几遍,不过好久没看有点忘记了,不过这次看也是非常得心应手。项目中也准备引入Swift,所以作者再次详细看了The Swift Programming Language (Swift 4.0.3)英文官方文档一遍,并且详细列举了本人认为大家比较常用并且应该掌握的所有知识点。这里不做深入探究,如果哪里不懂的话,可以自行深入研究。

所有知识点

  • 数组可以用“+”表示两个数组组合
  • 字符串截取等操作很简洁

    1
    2
    3
    4
    let greeting = "Hello, world!"
    let index = greeting.index(of: ",") ?? greeting.endIndex
    let beginning = greeting[..<index]
    // beginning is "Hello"
  • Dictionary可以遍历,并且支持移除操作

    1
    2
    3
    airports["APL"] = nil
    removeValue(forKey:)

遍历:

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

  • switch语法很强大,很灵活,支持任何类型,比如字符串、范围、管道等等。而且不用break语句

    1
    2
    3
    4
    case "a", "A":
    case 1..<5:
    case (-2...2, -2...2)
    case let (x, y) where x == y
  • guard关键词使用使语句更简单明了

  • #available判断api版本更简洁

    1
    2
    3
    4
    5
    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
    }
  • 函数可以返回多个值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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)
    }
  • 函数参数可以设置默认值

    1
    2
    3
    4
    5
    6
    func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // If you omit the second argument when calling this function, then
    // the value of parameterWithDefault is 12 inside the function body.
    }
    someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
    someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
  • 可变参数...

    1
    2
    3
    4
    5
    6
    7
    8
    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)
  • inout 可以修改外部变量。与c语言指针有点类似

    1
    2
    3
    4
    func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
  • 函数可以与属性变量一样对待。可以传递、取值等

  • 闭包(Closures)与Block类似
1
2
3
{ (parameters) -> return type in
statements
}

*@escaping@autoclosure修饰闭包
@escaping使闭包在函数执行结束之前不会被执行。

1
2
3
4
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)//闭包没有执行,而是加到数组中了
}

@autoclosure简化了闭包的代用,不过代码会变的难懂,苹果建议尽量不使用

1
2
3
4
5
6
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"

使用之后:

1
2
3
4
5
6
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))//大括号没有啦
// Prints "Now serving Ewa!"

  • 枚举功能很强大,很灵活,可以枚举的类型非常多,比如stringcharacterinteger
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
    }
    var productBarcode = Barcode.upc(8, 85909, 51226, 3)
    switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
    print("QR code: \(productCode).")
    }
1
2
3
enum Planet: Int{}
enum ASCIIControlCharacter: Character {}
enum CompassPoint: String {}
  • indirect表示枚举中使用了自己
    1
    2
    3
    4
    5
    enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
    }


1
2
3
4
5
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}

  • struct&&class
    struct传递是值传递;class是引用传递

    In Swift, many basic data types such as String, Array, and Dictionary are implemented as structures. This means that data such as strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.

  • ===和!==用来比较对象

  • lazy懒加载,使用的时候再加载
  • 仅读属性。将get、set移除,直接返回,可以用来实例单例

    1
    2
    3
    4
    5
    6
    struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
    return width * height * depth
    }
    }
  • mutating用来修改struct和enum。因为二者是不能不能被自己的实例对象修改属性变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
    x += deltaX
    y += deltaY
    }
    }
    var somePoint = Point(x: 1.0, y: 1.0)
    somePoint.moveBy(x: 2.0, y: 3.0)
    print("The point is now at (\(somePoint.x), \(somePoint.y))")
    // Prints "The point is now at (3.0, 4.0)"
    **注意let不能修改**
    let fixedPoint = Point(x: 3.0, y: 3.0)
    fixedPoint.moveBy(x: 2.0, y: 3.0)
    // this will report an error
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight is now equal to .high
ovenLight.next()
// ovenLight is now equal to .off
  • classstatic都可修饰类方法,class修饰的可以被子类重写
  • 脚标(Subscripts)。可以类、结构体、枚举定义脚标从而快速访问属性等。

    1
    2
    3
    4
    5
    6
    7
    8
    subscript(index: Int) -> Int {
    get {
    // return an appropriate subscript value here
    }
    set(newValue) {
    // perform a suitable setting action here
    }
    }
  • final可以防止被子类继承。

  • deinit 只有类有,当类销毁时会被回调。
  • ?是否为nil;??设置默认值
  • 异常处理
    1
    2
    3
    4
    5
    6
    7
    8
    do {
    try expression
    statements
    } catch pattern 1 {
    statements
    } catch pattern 2 where condition {
    statements
    }

try!明确知道不会抛出异常。

  • defer代码块执行后必须执行的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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.
    }
    }
  • is判断是否某个类型;as?as!转换至某个类型

  • Extensions与oc的category类似

    1
    2
    3
    extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
    }
  • Protocols

    1
    2
    3
    protocol SomeProtocol {
    // protocol definition goes here
    }

使用

1
2
3
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}

1
2
3
4
protocol SomeProtocol {
var mustBeSettable: Int { get set }//有get和set方法
var doesNotNeedToBeSettable: Int { get }//只有get方法,不能单独设置,只能在初始化的时候设置。
}
  • 检查是否遵循了某个协议

    • is遵循了返回true,否则返回false
    • as?遵循了正常转换,否则为nil
    • as!遵循了正常转换,否则抛出错误
  • 泛型(Generic);通常使用TUV等大写字母表示。

    1
    2
    3
    func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
    }
  • weakunowned(与oc的unsafe_unretained类似)解决循环应用的问题

    1
    weak var tenant: Person?
  • 访问控制权限(open > public > interal > fileprivate > private)

    • private

      private 访问级别所修饰的属性或者方法只能在当前类里访问。
      (注意:Swift4 中,extension 里也可以访问 private 的属性。)

    • fileprivate

      fileprivate 访问级别所修饰的属性或者方法在当前的 Swift)

    • internal(默认访问级别,internal修饰符可写可不写)

      internal 访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。
      如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。
      如果是 App 代码,也是在整个 App 代码,也是在整个 App 内部可以访问。

    • public

      可以被任何人访问。但其他 module 中不可以被 override 和继承,而在 module 内可以被 override 和继承。

    • open

      可以被任何人使用,包括 override 和继承。

0%