Swift 5.1

首發:cc loggit

又是一篇遲來的文章。主要是譯自: What’s new in Swift 5.1github

閱讀以前能夠查看我以前總結的Swift 3 到Swift 5的新特性swift

Swift5.1支持了SwiftUI, 能夠看出本次的更新更多了是爲了更好的「聲明」UI。api


改進自動生成的struct初始化方法

swift早期版本中支持了自動生成struct的初始化方法數組

struct User {
    var name: String
    var loginCount: Int = 0
}

let piper = User(name: "Piper Chapman", loginCount: 0)
複製代碼

Swift 5.1改進了初始化方法,若是屬性有了初始值,初始化的時候能夠省略。app

let gloria = User(name: "Gloria Mendoza", loginCount: 0)
let suzanne = User(name: "Suzanne Warren")
複製代碼

單行函數隱式返回

這點實際上很好理解,Swift 5.1中單行返回函數能夠省略return關鍵詞。dom

let doubled1 = [1, 2, 3].map { $0 * 2 }
let doubled2 = [1, 2, 3].map { return $0 * 2 }
複製代碼

上面兩個是等價的。ide

實際上下面這麼寫也同樣函數

func double(_ number: Int) -> Int {
    number * 2
}
複製代碼

更通用的Self

Swift 5.1中擴展了Self的使用,在class,struct, enmu中使用時候能夠指向這個類型。這點在動態類型中頗有用,特別是某些類型須要在運行時才能決定時候。ui

例如,下面場景中

class NetworkManager {
    class var maximumActiveRequests: Int {
        return 4
    }

    func printDebugData() {
        print("Maximum network requests: \(NetworkManager.maximumActiveRequests).")
    }
}
複製代碼

上面聲明瞭靜態的maximumActiveRequests屬性,而且使用實例方法printDebugData來打印這個屬性。如今這樣工做的挺好。可是若是NetworkManager有子類,狀況就不同了

class ThrottledNetworkManager: NetworkManager {
    override class var maximumActiveRequests: Int {
        return 1
    }
}
複製代碼

子類改變了maximumActiveRequests,可是若是咱們調用printDebugData(),它只會打印父類的屬性。

let manager = ThrottledNetworkManager()
manager.printDebugData()
複製代碼

它理應打印1而不是4,這就是Self要解決的問題。咱們改寫printDebugData()Self(大寫S)來指向當前的類型:

class ImprovedNetworkManager {
    class var maximumActiveRequests: Int {
        return 4
    }

    func printDebugData() {
        print("Maximum network requests: \(Self.maximumActiveRequests).")
    }
}
複製代碼

Self在協議中仍然像早期Swift中同樣工做。

不透明返回類型(Opaque Return types)

提案SE-0244爲Swift 5.1帶來了不透明類型:知曉某個對象的能力可是不須要知道這個對象的具體類型。

初看之下,它很像協議protocol,但不透明返回類型走的比這更遠,它能夠和associated type使用。

protocol Fighter { }
struct XWing: Fighter { }

func launchFighter() -> Fighter {
    return XWing()
}

let red5 = launchFighter()
複製代碼

上面launchFighter返回某種Fighter,可是不知道具體那個類型,它能夠是XWing,或者咱們新增一個strunct YWing:Fighter {}

這樣寫有個問題,若是你想知道red5具體是那種類型的飛機呢?你可能想到方案是,讓Fighter遵循Equatable協議,而後咱們就可使用==方法。可是實際使用的時候會發現下面的報錯:

「Protocol 'Fighter' can only be used as a generic constraint because it has Self or associated type requirements.」

這是由於Equatable有一個Self的associated type。 有associated type的協議看起來像類型,可是它們實際上不是,它們實際上表示的是「遵循此協議的任意類型」

Swift 5.1中的不透明返回類型,能夠將這種協議做作一個普通的類型來使用。只須要在協議名前增長some關鍵詞。

func launchOpaqueFighter() -> some Fighter {
    return XWing()
}
複製代碼

不透明返回類型(Opaque Return types)能夠帶來的好處有:

  • 咱們的函數決定具體的返回類型,而不是函數的調用方。
  • 咱們不須要在關心Self或者associated type,由於編譯器會明確知道內部具體的類型。
  • 爲函數定義方未來改變實現留有餘地。
  • 函數定義方不須要對外保留內部的類型。

支持Staticclass類下標(subscripts)

靜態Static類型的屬性和方法,可用來在類型全部實例間共享某些值。例如你能夠在你的App中集中管理配置。

public enum OldSettings {
    private static var values = [String: String]()

    static func get(_ name: String) -> String? {
        return values[name]
    }

    static func set(_ name: String, to newValue: String?) {
        print("Adjusting \(name) to \(newValue ?? "nil")")
        values[name] = newValue
    }
}

OldSettings.set("Captain", to: "Gary")
OldSettings.set("Friend", to: "Mooncake")
print(OldSettings.get("Captain") ?? "Unknown")
複製代碼

字典包裹在類型中可讓更當心的控制它,而且使用沒有caseenum,也就讓你無法實例化Settings

在Swift 5.1中你可使用static subscript

public enum NewSettings {
    private static var values = [String: String]()

    public static subscript(_ name: String) -> String? {
        get {
            return values[name]
        }
        set {
            print("Adjusting \(name) to \(newValue ?? "nil")")
            values[name] = newValue
        }
    }
}

NewSettings["Captain"] = "Gary"
NewSettings["Friend"] = "Mooncake"
print(NewSettings["Captain"] ?? "Unknown")
複製代碼
  • 類型實例以前就能夠自定義下標
  • swift 5.1中類型也能夠定製static或者class的下標了。

static或者class都是靜態的前綴,區別是,class允許子類型覆蓋

swift中`static`或者`class`方法的區別

告警有歧義的none

Swift的可選(optional)是現實是經過有兩個值somenone的enum來實現的。這樣就和咱們本身代碼中有nonecase的enum包裹在optional時候產生混淆。

enum BorderStyle {
    case none
    case solid(thickness: Int)
}
複製代碼

若是在非可選值中使用

let border1: BorderStyle = .none
print(border1)
複製代碼

上面會打印none。 可是若是咱們在使用在可選值中,咱們不知道什麼邊框時候,Swift 5.1以前的版本會有問題。

let border2: BorderStyle? = .none
print(border2)
複製代碼

會打印nil, 由於swfit會默認將.none推導爲可選是空值,而不是BorderStyle.none

Swift 5.1中會對此作出警告:「Assuming you mean 'Optional.none'; did you mean 'BorderStyle.none' instead?」,提示你做修復。

匹配可選(optional)和非可選的(non-optional)的enmu

Swift一直可以在switch case聰明的處理可選(optional)和非可選的(non-optional)的string,和integer。到了Swift 5.1 也支持enum了。

enum BuildStatus {
    case starting
    case inProgress
    case complete
}

let status: BuildStatus? = .inProgress

switch status {
case .inProgress:
    print("Build is starting…")
case .complete:
    print("Build is complete!")
default:
    print("Some other build status")
}
複製代碼

如今可以正常的打印,」Build is starting…「了。

可排序集合的diff

Swift 5.1 爲可排序集合(內含Equatable元素)提供了一個difference(from:)方法來計算兩個集合,那個元素被移除了,新增了哪一個……

此方法被標註爲,swift 5.1才@available,所以使用須要if swift(>=5.1)來判斷

let operatingSystems = ["Yosemite",
                        "El Capitan",
                        "Sierra",
                        "High Sierra",
                        "Mojave",
                        "Catalina"]
var answers = ["Mojave",
               "High Sierra",
               "Sierra",
               "El Capitan",
               "Yosemite",
               "Mavericks"]


#if swift(>=5.1)
let differences = operatingSystems.difference(from: answers)
let sameAnswers = answers.applying(differences) ?? []
// 1
for change in differences.inferringMoves() {
  switch change {
    // 2
    case .insert(let offset, let element, let associatedWith):
      answers.insert(element, at: offset)
      guard let associatedWith = associatedWith else {
        print("\(element) inserted at position \(offset + 1).")
        break
      }
      print("""
            \(element) moved from position \(associatedWith + 1) to position
            \(offset + 1).
            """)
    // 3
    case .remove(let offset, let element, let associatedWith):
      answers.remove(at: offset)
      guard let associatedWith = associatedWith else {
        print("\(element) removed from position \(offset + 1).")
        break
      }
      print("""
            \(element) removed from position \(offset + 1) because it should be
              at position \(associatedWith + 1).
            """)
  }
}
#endif
複製代碼
  • 使用inferringMoves()獲得diff中所欲改變
  • 經過associatedWith不爲nil.insert(offset:element:associatedWith:)來判斷是插入的操做
  • 經過associatedWith不爲nil.remove(offset:element:associatedWith:)來判斷是刪除的操做

這個功能確實很是的pro哈~~

建立沒有初始值的數組(uninitialized arrays)

能夠在Swfift 5.1的版本中建立一個沒有初始值的數組。

// 1
let randomSwitches = Array<String>(unsafeUninitializedCapacity: 5) {
  buffer, count in
  // 2
  for i in 0..<5 {
    buffer[i] = Bool.random() ? "on" : "off"
  }
  // 3
  count = 5
}
複製代碼
  1. 使用init(unsafeUninitializedCapacity:initializingWith:)來建立一個初始大小的數組
  2. 循環該數組(randomSwitches), 給每一個值設值。
  3. 第二個inout參數可讓你從新爲數組設置長度。

總結

這些就是swift 5.1的更新了,不算難懂,確實讓swift愈來愈好用。😄

相關文章
相關標籤/搜索