<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    Swift 5.5 新特性搶先看,async/await 將重磅來襲

    共 16413字,需瀏覽 33分鐘

     ·

    2021-06-06 16:57

    ????關注后回復 “進群” ,拉你進程序員交流群????


    作者丨小集

    來源丨知識小集(ID:zsxjtip)


    再過一周的時間,WWDC21 就正式舉行了,如果不出意外的話,Swift 5.5 測試版也會在期間發(fā)布。早在 3 月 13 日,官方論壇就公布了 Swift 5.5 版本的發(fā)布計劃,并在 4 月 16 日拉出了 release/5.5 分支。經過幾個月時間的準備,從 Swift Evolution 中,我們能發(fā)現(xiàn) Swift 5.5 將為我們帶來許多期待已久的特性,如 async/await。我們今天就來簡單整理一下這些 可能 將在 Swift 5.5 中出現(xiàn)的新特性。

    SE-0291 包集合

    這個 proposal 旨在為 SwiftPM 添加對包集合的支持。包集合是包和相關元數據的列表,可以更輕松地發(fā)現(xiàn)特定用例的現(xiàn)有包。SwiftPM 將允許用戶訂閱這些集合,通過 swift package-collection 命令行界面搜索它們,并使 libSwiftPM 的任何客戶端都可以訪問它們的內容。這個 proposal 關注于以命令行界面和包集合想著的配置數據格式。

    例如,list 命令將列出用戶配置的所有集合:

    $ swift package-collection list [--json]
    My organisation's packages - https://example.com/packages.json
    ...

    describe 命令顯示來自包本身的元數據。

    $ swift package-collection describe [--json] https://github.com/jpsim/yams
    Description: A sweet and swifty YAML parser built on LibYAML.
    Available Versions: 4.0.0, 3.0.0, ...
    Watchers: 14
    Readme: https://github.com/jpsim/Yams/blob/master/README.md
    Authors: @norio-nomura, @jpsim
    --------------------------------------------------------------
    Latest Version: 4.0.0
    Package Name: Yams
    Modules: Yams, CYaml
    Supported Platforms: iOS, macOS, Linux, tvOS, watchOS
    Supported Swift Versions: 5.3, 5.2, 5.1, 5.0
    License: MIT
    CVEs: ...

    https://github.com/apple/swift-evolution/blob/main/proposals/0291-package-collections.md

    SE-0293 將屬性包裝器擴展到函數和閉包參數

    Property Wrappers 用于抽象出常見的屬性訪問器模式,在 Swift 5.1 中引入。不過之前僅允許在局部變量和類型屬性上應用屬性包裝器。而這個 proposal 的目標是將屬性包裝器擴展到函數和閉包參數。

    例如,使用來自 PropertyKit 的驗證,我們可以將各種前提條件抽象到一個屬性包裝器中:

    @propertyWrapper
    struct Asserted<Value> {
    init(
    wrappedValue: Value,
    validation: Validation<Value>,
    ) { ... }

    var wrappedValue: Value { ... }
    }

    將 @Asserted 應用于參數以對參數值斷言某些先決條件會很有用。例如,下面的代碼斷言傳遞給 quantity 參數的參數大于或等于1:

    func buy(
    @Asserted(.greaterOrEqual(1)) quantity: Int,
    of product: Product,
    ) { ... }

    https://github.com/apple/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md

    SE-0295 有關聯(lián)值的枚舉的 Codable 合成

    在 SE-0166 中引入了 Codable,它支持合成類和結構類型的 Encodable 和 Decodable 一致性,其中僅包含也符合各自協(xié)議的值。

    這個 proposal 將擴展對枚舉關聯(lián)值的一致性的自動合成的支持。

    如以下枚舉有關聯(lián)值:

    enum Command: Codable {
    case load(key: String)
    case store(key: String, value: Int)
    }

    將會被編碼為

    {
    "load": {
    "key": "MyKey"
    }
    }

    {
    "store": {
    "key": "MyKey",
    "value": 42
    }
    }

    編譯器將生成以下 CodingKeys 聲明:

    // contains keys for all cases of the enum
    enum CodingKeys: CodingKey {
    case load
    case store
    }

    // contains keys for all associated values of `case load`
    enum LoadCodingKeys: CodingKey {
    case key
    }

    // contains keys for all associated values of `case store`
    enum StoreCodingKeys: CodingKey {
    case key
    case value
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0295-codable-synthesis-for-enums-with-associated-values.md

    SE-0296 async/await

    現(xiàn)代 Swift 開發(fā)涉及大量使用閉包和完成處理程序的異步編程,但這些 API 都很難使用。當使用許多異步操作、錯誤處理或異步調用之間的控制流變得復雜時,會讓問題變得很復雜。我們先看一個簡單的例子:

    // 一系列簡單的異步操作通常需要深度嵌套的閉包
    func processImageData1(completionBlock: (_ result: Image) -> Void) {
    loadWebResource("dataprofile.txt") { dataResource in
    loadWebResource("imagedata.dat") { imageResource in
    decodeImage(dataResource, imageResource) { imageTmp in
    dewarpAndCleanupImage(imageTmp) { imageResult in
    completionBlock(imageResult)
    }
    }
    }
    }
    }

    processImageData1 { image in
    display(image)
    }

    而這個提案則引入了一種語言擴展,大大簡化了這些操作,讓代碼更加自然而不易出錯。這種設計為 Swift 引入了一個協(xié)程模型。函數可以是 async,允許程序員使用正常的控制流機制編寫涉及異步操作的復雜邏輯。編譯器負責將異步函數轉換為一組合適的閉包和狀態(tài)機。實際上 async/await 語義早已是現(xiàn)代編程語言的標配。我們來看看,async/await 如何讓代碼變得更加簡潔:

    func loadWebResource(_ path: String) async throws -> Resource
    func decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image
    func dewarpAndCleanupImage(_ i : Image) async throws -> Image

    func processImageData() async throws -> Image {
    let dataResource = try await loadWebResource("dataprofile.txt")
    let imageResource = try await loadWebResource("imagedata.dat")
    let imageTmp = try await decodeImage(dataResource, imageResource)
    let imageResult = try await dewarpAndCleanupImage(imageTmp)
    return imageResult
    }

    不過,這個 proposal 并不提供并發(fā),結構化并發(fā)問題由另一個 proposal 引入,它將異步函數與并發(fā)執(zhí)行的任務相關聯(lián),并提供用于創(chuàng)建、查詢和取消任務的 API。

    https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md

    SE-0297 與 Objective-C 的并發(fā)互操作性

    在 Apple 平臺上,Swift 與 Objective-C 的混編與交互目前來講還是一個很大的課題。在 Objective-C 中,異步 API 隨處可見,在 iOS 14.0 SDK 中就包含了近 1000 個接受 completion 處理器的方法。例如以下 PassKit API 中的方法

    - (void)signData:(NSData *)signData 
    withSecureElementPass:(PKSecureElementPass *)secureElementPass
    completion:(void (^)(NSData *signedData, NSData *signature, NSError *error))completion;

    這些方法包括可以直接在 Swift 中調用的方法,可以在 Swift 定義的子類中覆蓋的方法,以及可以實現(xiàn)的協(xié)議中的方法。

    當前,以上 Objective-C 函數在 Swift 中會被翻譯成以下函數:

    @objc func sign(_ signData: Data, 
    using secureElementPass: PKSecureElementPass,
    completion: @escaping (Data?, Data?, Error?) -> Void
    )

    這個 proposal 旨在為 Swift 并發(fā)結構與 Objective-C 之間提供互操作性,并實現(xiàn)以下目標:

    • 將 Objective-C 完成處理程序方法轉換為 Swift 中的 async 方法;

    • 允許將 Swift 中定義的 async 方法標記為 @objc,在這種情況下,它們將作為完成處理程序方法導出;

    • 提供 Objective-C 屬性來控制如何將基于完成處理程序的 API 轉換為 asyncSwift 函數。

    基于這些假設,以上 Objective-C 函數將會被翻譯為以下 async 函數:

    @objc func sign(
    _ signData: Data,
    using secureElementPass: PKSecureElementPass
    )
    async throws -> (Data, Data)

    同時可以通過以下方式來調用:

    let (signedValue, signature) = try await passLibrary.sign(signData, using: pass)

    https://github.com/apple/swift-evolution/blob/main/proposals/0297-concurrency-objc.md

    SE-0298 Async/Await: 序列

    SE-0296 的 async/await 特性為 Swift 提供了更直觀的異步編程方式。而這個 proposal 的目標是基于 async/await,以內置的方式更直觀地編寫和使用隨時間返回多個值的函數。

    這個 proposal 主要由三個部分組成:

    • 表示異步值序列的協(xié)議的標準庫定義;

    • 編譯器支持在異步值序列上使用 for...in 語法;

    • 對異步值序列進行操作的常用函數的標準庫實現(xiàn)

    基于這個 proposal,迭代異步值序列像迭代同步值序列一樣簡單。一個示例用例是迭代文件中的行,如下所示:

    for try await line in myFile.lines() {
    // Do something with each line
    }

    為此,標準庫中定義了以下協(xié)議

    public protocol AsyncSequence {
    associatedtype AsyncIterator: AsyncIteratorProtocol where AsyncIterator.Element == Element
    associatedtype Element
    __consuming func makeAsyncIterator() -> AsyncIterator
    }

    public protocol AsyncIteratorProtocol {
    associatedtype Element
    mutating func next() async throws -> Element?
    }

    編譯器生成的代碼將允許在符合 AsyncSequence 的任何類型上使用for in循環(huán)。標準庫還將擴展協(xié)議以提供熟悉的通用算法。如以下示例:

    struct Counter : AsyncSequence {
    let howHigh: Int

    struct AsyncIterator : AsyncIteratorProtocol {
    let howHigh: Int
    var current = 1
    mutating func next() async -> Int? {
    // We could use the `Task` API to check for cancellation here and return early.
    guard current <= howHigh else {
    return nil
    }

    let result = current
    current += 1
    return result
    }
    }

    func makeAsyncIterator() -> AsyncIterator {
    return AsyncIterator(howHigh: howHigh)
    }
    }

    在調用端,則可以如下使用:

    for await i in Counter(howHigh: 3) {
    print(i)
    }

    /*
    Prints the following, and finishes the loop:
    1
    2
    3
    */



    for await i in Counter(howHigh: 3) {
    print(i)
    if i == 2 { break }
    }
    /*
    Prints the following:
    1
    2
    */

    https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md

    SE-0299 在通用上下文中擴展靜態(tài)成員查找

    Swift 支持對具體類型的靜態(tài)成員查找,并通過類似枚舉的 . 語法來調用。例如,SwiftUI 中使用預定義的常用值作為靜態(tài)屬性擴展了 Font 和 Color 等類型。

    extension Font {
    public static let headline: Font
    public static let subheadline: Font
    public static let body: Font
    ...
    }

    extension Color {
    public static let red: Color
    public static let green: Color
    public static let blue: Color
    ...
    }

    可通過以下方式來調用:

    VStack {
    Text(item.title)
    .font(.headline)
    .foregroundColor(.primary)
    Text(item.subtitle)
    .font(.subheadline)
    .foregroundColor(.secondary)
    }

    不過,靜態(tài)成員查找目前存在一個問題:不支持泛型函數中的協(xié)議成員,所以沒有辦法使用 . 語法來調用,如 SwiftUI 定義了一個 toggleStyle 視圖裝飾器:

    extension View {
    public func toggleStyle<S: ToggleStyle>(_ style: S) -> some View
    }

    public protocol ToggleStyle {
    associatedtype Body: View
    func makeBody(configuration: Configuration) -> Body
    }

    public struct DefaultToggleStyle: ToggleStyle { ... }
    public struct SwitchToggleStyle: ToggleStyle { ... }
    public struct CheckboxToggleStyle: ToggleStyle { ... }

    目前的調用方式是,在使用 toggleStyle 修飾符時將具體類型以全名方式寫入 ToggleStyle:

    Toggle("Wi-Fi", isOn: $isWiFiEnabled)
    .toggleStyle(SwitchToggleStyle())

    而這個 proposal 的目標是放寬對協(xié)議上訪問靜態(tài)成員的限制,讓泛型 API 具有更好的可讀性,即通過以下方式來調用:

    Toggle("Wi-Fi", isOn: $isWiFiEnabled)
    .toggleStyle(.switch)

    https://github.com/apple/swift-evolution/blob/main/proposals/0299-extend-generic-static-member-lookup.md

    SE-0300 異步任務與同步代碼接口

    異步 Swift 代碼需要能夠與使用諸如完成回調和委托方法之類的技術的現(xiàn)有同步代碼一起工作以響應事件。異步任務可以將自己暫停,然后同步代碼可以捕獲并調用它們以響應事件來恢復任務。

    標準庫將提供 API 來獲取當前異步任務的延續(xù),這會掛起任務,并產生一個值,同步代碼隨后可以通過該值使用句柄來恢復任務。例如

    func beginOperation(completion: (OperationResult) -> Void)

    我們可以通過掛起任務并在調用回調時使用其連續(xù)性將其恢復為異步接口,然后將傳遞給回調的參數轉換為異步函數的正常返回值:

    func operation() async -> OperationResult {
    // Suspend the current task, and pass its continuation into a closure
    // that executes immediately
    return await withUnsafeContinuation { continuation in
    // Invoke the synchronous callback-based API...
    beginOperation(completion: { result in
    // ...and resume the continuation when the callback is invoked
    continuation.resume(returning: result)
    })
    }
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0300-continuation.md

    SE-0304 結構化并發(fā)

    async/await proposal 本向并沒有引入并發(fā)性:它只是忽略異步函數中的掛起點,它將以與同步函數基本相同的方式執(zhí)行。而這個 proposal 的目標就是在 Swift 中引入結構化并發(fā)的支持,并允許高效實現(xiàn)的模型來并發(fā)執(zhí)行異步代碼。

    例如以下一段準備晚餐的代碼:

    func chopVegetables() async throws -> [Vegetable] { ... }
    func marinateMeat() async -> Meat { ... }
    func preheatOven(temperature: Double) async throws -> Oven { ... }

    // ...

    func makeDinner() async throws -> Meal {
    let veggies = try await chopVegetables()
    let meat = await marinateMeat()
    let oven = try await preheatOven(temperature: 350)

    let dish = Dish(ingredients: [veggies, meat])
    return try await oven.cook(dish, duration: .hours(3))
    }

    makeDinner 中的每個步驟都是異步操作,不過整個流程每個點都會暫停,直到當前步驟完成。而為了更快地準備好晚餐,我們需要同時執(zhí)行其中一些步驟,為此,可以將步驟分解為可以并行發(fā)生的不同任務。而這個 proposal 所提的結構化并發(fā),就可以完成這種任務。proposal 中的概念很多,在此不詳細介紹。在使用結構化并發(fā)對上述代碼改造后,代碼類似于以下:

    func makeDinner() async throws -> Meal {
    // Prepare some variables to receive results from our concurrent child tasks
    var veggies: [Vegetable]?
    var meat: Meat?
    var oven: Oven?

    enum CookingStep {
    case veggies([Vegetable])
    case meat(Meat)
    case oven(Oven)
    }

    // Create a task group to scope the lifetime of our three child tasks
    try await withThrowingTaskGroup(of: CookingStep.self)
    { group in
    group.async {
    try await .veggies(chopVegetables())
    }
    group.async {
    await .meat(marinateMeat())
    }
    group.async {
    try await .oven(preheatOven(temperature: 350))
    }

    for try await finishedStep in group {
    switch finishedStep {
    case .veggies(let v): veggies = v
    case .meat(let m): meat = m
    case .oven(let o): oven = o
    }
    }
    }

    // If execution resumes normally after `withTaskGroup`, then we can assume
    // that all child tasks added to the group completed successfully. That means
    // we can confidently force-unwrap the variables containing the child task
    // results here.
    let dish = Dish(ingredients: [veggies!, meat!])
    return try await oven!.cook(dish, duration: .hours(3))
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0304-structured-concurrency.md

    SE-0306 Actors

    Swift 并發(fā)模型旨在提供一種安全的編程模型,該模型可靜態(tài)檢測數據競爭和其他常見的并發(fā)錯誤。結構化并發(fā)提議引入了一種定義并發(fā)任務的方法,并為函數和閉包提供了數據爭用安全性。該模型適用于許多常見的設計模式,包括諸如并行映射和并發(fā)回調模式之類,但僅限于使用由閉包捕獲的狀態(tài)。

    Swift 包含一些類,這些類提供了一種聲明可變狀態(tài)的機制,這些狀態(tài)可以在程序之間共享。然而,類很難在并發(fā)程序中正確使用,需要手動同步以避免數據競爭。我們希望提供使用共享可變狀態(tài)的功能,同時仍提供對數據競爭和其他常見并發(fā)錯誤的靜態(tài)檢測。

    actor 模型定義了稱為該角色的實體,非常適合此任務。Actor 允許聲明并發(fā)域中包含的狀態(tài)包,然后定義對其執(zhí)行操作的多個操作。每個 actor 都通過數據隔離來保護自己的數據,從而確保即使在許多客戶端同時發(fā)出參與者請求的情況下,在給定的時間也只有一個線程可以訪問該數據。作為 Swift 并發(fā)模型的一部分,actor 提供了與結構化并發(fā)相同的競爭和內存安全屬性。

    actor 是一種引用類型,可保護對其可變狀態(tài)的訪問,并隨關鍵字 actor 一起引入:

    actor BankAccount {
    let accountNumber: Int
    var balance: Double

    init(accountNumber: Int, initialDeposit: Double) {
    self.accountNumber = accountNumber
    self.balance = initialDeposit
    }
    }

    像其他 Swift 類型一樣,actor 可以有初始化器,方法,屬性和下標。它們可以擴展并符合協(xié)議,可以是通用的,也可以與通用一起使用。

    主要區(qū)別在于 actor 可以保護其狀態(tài)免受數據爭奪。這是 Swift 編譯器通過強制使用 actor 及其實例成員的方式受到一系列限制而靜態(tài)地強制實施的,統(tǒng)稱為 actor 隔離。

    https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md

    SE-0307 允許互換使用 CGFloat 和 Double 類型

    Swift 首次發(fā)布時,CGFloat 的類型的使用就是一項挑戰(zhàn)。當時,大多數 iOS 設備仍為 32 位。諸如 CoreGraphics 之類的 SDK 提供的 API 在 32 位平臺上采用 32 位浮點值,在 64 位平臺上采用 64 位值。首次引入這些 API 時,在 32 位平臺上 32 位標量算術速度更快,但是到 Swift 發(fā)行時,情況已不再如此:直到今天, 64 位標量算術速度與 32 位一樣快。甚至在 32 位平臺上也是如此。之所以仍然保留了 32/64 位分割,主要是出于源和 ABI 穩(wěn)定性的原因。

    而這個 proposal 目標是允許 Double 和 CGFloat 類型通過將一種類型透明轉換為另一種類型。

    https://github.com/apple/swift-evolution/blob/main/proposals/0307-allow-interchangeable-use-of-double-cgfloat-types.md

    SE-0308 #if 支持后綴成員表達式

    Swift 有條件編譯塊 #if ... #endif,它允許根據一個或多個編譯條件的值對代碼進行條件編譯。當前,與 C 語言中的 #if 不同的是,每個子句的主體必須包含完整的語句。但是,在某些情況下,尤其是在結果生成器上下文中,出現(xiàn)了將 #if 應用于部分表達式的需求。這個該 proposal 擴展了 #if ... #endif以便能夠包圍后綴成員表達式。

    例如當前使用的如下代碼:

    VStack {
    let basicView = Text("something")
    #if os(iOS)
    basicView
    .iOSSpecificModifier()
    .commonModifier()
    #else
    basicView
    .commonModifier()
    #endif
    }

    可以改成以下這種方式

    VStack {
    Text("something")
    #if os(iOS)
    .iOSSpecificModifier()
    #endif
    .commonModifier()
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0308-postfix-if-config-expressions.md

    SE-0310 有效的只讀屬性

    異步函數旨在用于可能會或始終會在返回之前暫停執(zhí)行上下文切換的計算,但缺乏有效的只讀計算屬性和下標,因此這個 proposal 升級了 Swift 的只讀屬性以支持異步并單獨或一起拋出關鍵字,從而使它們明顯更靈活。

    為了說明這一點,我們可以創(chuàng)建一個 BundleFile 結構體,嘗試將其內容加載到應用程序的資源包中。由于文件可能不存在,或者可能存在但由于某種原因而無法讀取,或者可能可讀但太大,因此需要花費一些時間才能讀取,因此我們可以將 contents 屬性標記為異步拋出,如下所示:

    enum FileError: Error {
    case missing, unreadable
    }

    struct BundleFile {
    let filename: String

    var contents: String {
    get async throws {
    guard let url = Bundle.main.url(forResource: filename, withExtension: nil) else {
    throw FileError.missing
    }

    do {
    return try String(contentsOf: url)
    } catch {
    throw FileError.unreadable
    }
    }
    }
    }

    因為 content 既是異步的又是拋出的,所以我們在嘗試讀取它時必須使用 try await:

    func printHighScores() async throws {
    let file = BundleFile(filename: "highscores")
    try await print(file.contents)
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md

    SE-0316 全局 actors

    Actor 非常適合隔離實例數據,但是當需要隔離的數據分散在整個程序中,或者表示程序外部存在的某種狀態(tài)時,將所有代碼和數據都放入單個actor 實例中可能是不切實際的(例如,大型程序)甚至是不可能的(與那些假設無處不在的系統(tǒng)進行交互時)。

    global actors 的主要目標是將 actor 模型應用于只能由主線程訪問的狀態(tài)和操作。在應用程序中,主線程通常負責執(zhí)行主要的事件處理循環(huán),該循環(huán)處理來自各種來源的事件并將其傳遞給應用程序代碼。global actors 提供了一種機制,可以利用 actor 的角色來描述主線程,利用 Swift 的 actor 隔離模型來幫助正確使用主線程。

    @MainActor var globalTextSize: Int

    @MainActor func increaseTextSize() {
    globalTextSize += 2 // okay:
    }

    func notOnTheMainActor() async {
    globalTextSize = 12 // error: globalTextSize is isolated to MainActor
    increaseTextSize() // error: increaseTextSize is isolated to MainActor, cannot call synchronously
    await increaseTextSize() // okay: asynchronous call hops over to the main thread and executes there
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0316-global-actors.md

    SE-0317 async let bindings

    結構化并發(fā)提供了一個范式,用于在有范圍的任務組中生成并發(fā)子任務,建立定義明確的任務層次結構,從而可以透明地處理并發(fā)管理的取消,錯誤傳播,優(yōu)先級管理和其他棘手的細節(jié)。

    這個 proposal 旨在使用類似于 let 綁定的輕量級語法,使生成子任務的常規(guī)任務異步運行,并將最終結果傳遞給父任務。

    還是以午餐為例,使用 async let,那么代碼看起來是下面這種:

    func makeDinner() async throws -> Meal {
    async let veggies = chopVegetables()
    async let meat = marinateMeat()
    async let oven = preheatOven(temperature: 350)

    let dish = Dish(ingredients: await [try veggies, meat])
    return try await oven.cook(dish, duration: .hours(3))
    }

    https://github.com/apple/swift-evolution/blob/main/proposals/0317-async-let.md

    小結

    這里只是整理了部分在 Swift 5.5 中實現(xiàn)的 proposal 或者是在當前 main 快照中審核的 proposal??梢钥吹?async/await 及一些異步模型將會是 Swift 5.5 的重點內容。當然,最終 Swift 5.5 會新增哪些特性,還需要等最后的結果。也許 Swift 團隊會將一些新特性放到 Swift 6 中發(fā)布。讓我們期待一下 WWDC21 吧。

    -End-

    最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網盤了,歡迎下載!

    點擊??卡片,關注后回復【面試題】即可獲取

    在看點這里好文分享給更多人↓↓

    瀏覽 61
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    午夜激情网 | 精品无码一区二区三区四区 | 西西4444www大胆艺术 | 欧美自拍视屏播放在线观看 | 我要操在线视频 |