帶你初識Swift4.0,踏入Swift的大門

FlyOceanFish發表於2018-01-25

背景

由於Swift4之前的版本也看過好幾遍,不過好久沒看有點忘記了,不過這次看也是非常得心應手。專案中也準備引入Swift,所以作者再次詳細看了The Swift Programming Language (Swift 4.0.3)英文官方文件一遍,並且詳細列舉了本人認為大家比較常用並且應該掌握的所有知識點。這裡不做深入探究,如果哪裡不懂的話,可以自行深入研究。

所有知識點

  • 陣列可以用“+”表示兩個陣列組合
  • 字串擷取等操作很簡潔
let greeting = "Hello, world!"
let index = greeting.index(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"
複製程式碼
  • Dictionary可以遍歷,並且支援移除操作
airports["APL"] = nil
或
removeValue(forKey:)
複製程式碼

遍歷:

for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}
複製程式碼
  • switch語法很強大,很靈活,支援任何型別,比如字串、範圍、管道等等。而且不用break語句
case "a", "A":
case 1..<5:
case (-2...2, -2...2)
case let (x, y) where x == y
複製程式碼
  • guard關鍵詞使用使語句更簡單明瞭
  • #available判斷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
}
複製程式碼
  • 函式可以返回多個值
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)
}
複製程式碼
  • 函式引數可以設定預設值
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
複製程式碼
  • 可變引數...
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語言指標有點類似
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA

複製程式碼
  • 函式可以與屬性變數一樣對待。可以傳遞、取值等
  • 閉包(Closures)與Block類似
{ (parameters) -> return type in
    statements
}
複製程式碼

*@escaping@autoclosure修飾閉包 @escaping使閉包在函式執行結束之前不會被執行。

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)//閉包沒有執行,而是加到陣列中了
}
複製程式碼

@autoclosure簡化了閉包的代用,不過程式碼會變的難懂,蘋果建議儘量不使用

// 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!"
複製程式碼

使用之後:

// 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
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).")
}
複製程式碼
enum Planet: Int{}
enum ASCIIControlCharacter: Character {}
enum CompassPoint: String {}
複製程式碼
  • indirect表示列舉中使用了自己
enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
複製程式碼

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移除,直接返回,可以用來例項單例
struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}
複製程式碼
  • mutating用來修改struct和enum。因為二者是不能不能被自己的例項物件修改屬性變數
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

複製程式碼
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)。可以類、結構體、列舉定義腳標從而快速訪問屬性等。
subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
    }
}
複製程式碼
  • final可以防止被子類繼承。
  • deinit 只有類有,當類銷燬時會被回撥。
  • ?是否為nil;??設定預設值
  • 異常處理
do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
}
複製程式碼

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.
    }
}

複製程式碼
  • is判斷是否某個型別;as?as!轉換至某個型別
  • Extensions與oc的category類似
extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}
複製程式碼
  • Protocols
protocol SomeProtocol {
    // protocol definition goes here
}

複製程式碼

使用

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}
複製程式碼
protocol SomeProtocol {
    var mustBeSettable: Int { get set }//有get和set方法
    var doesNotNeedToBeSettable: Int { get }//只有get方法,不能單獨設定,只能在初始化的時候設定。
}
複製程式碼
  • 檢查是否遵循了某個協議

    • is遵循了返回true,否則返回false
    • as?遵循了正常轉換,否則為nil
    • as!遵循了正常轉換,否則丟擲錯誤
  • 泛型(Generic);通常使用TUV等大寫字母表示。

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}
複製程式碼
  • weakunowned(與oc的unsafe_unretained類似)解決迴圈應用的問題
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 和繼承。

部落格

FlyOceanFish

相關文章