非同期/待機操作—非同期符号を書く新しい方法


async/waitメカニズムは、伝統的に補完ハンドラ(クロージャとして知られている)で書く非同期コードを書く新しい方法です.非同期関数を使用すると、非同期コードが同期しているかのように記述できます.デモンストレーション目的のために、我々は速い5.5バージョンでXcode 13 betaを使用しました.

非同期符号を書く新しい方法


async/waitが解決できる5つの主な問題は以下の通りです.
  • 運命のピラミッド
  • より良いエラー処理
  • 非同期関数の条件付き実行
  • 忘れたり誤ったりしてコールバックを呼び出す
  • 同期API APIのための同期APIの設計と性能問題の除去
  • async waitによって、非同期で並行した関数を実行するためのメカニズムを提供しますsoftware development .

    async / wait -完了ハンドラ


    まず、伝統的に補完ハンドラを使って関数を書きます.誰もがこのアプローチに精通している.
    私たちを誤解しないでください、これは完成ハンドラで関数を書く悪い方法ではありません.我々は何年もこのようなことをしてきたprojects ; 補完ハンドラは、Swiftコードで一般的に使用され、関数が戻った後に値を返すことができます.
    とはいえ、入れ子になっている多くの非同期操作があれば、あなたのコードに導入されたすべてのバグに関して、何か奇妙なことが起こっているかどうかを確認するのはSWIFTコンパイラにとって本当に簡単ではありません.
    きれいなコードのために、我々はNetworkManagerと呼ばれている新しい速いファイルを作りました.迅速かつ、このファイルでは、我々の要求を処理しています.ユーザーは、名前、電子メール、およびユーザー名の値を持つ構造体です.
    struct User: Codable {
        let name: String
        let email: String
        let username: String
    }
    
    // MARK: fetch users with completion handler
    func fetchUsersFirstExample(completion: @escaping (Result<[User], NetworkingError>) -> Void) {
    
        let usersURL = URL(string: Constants.url)
    
        guard let url = usersURL else {
    
            completion(.failure(.invalidURL))
            return
        }
    
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let _ = error {
                completion(.failure(.unableToComplete))
            }
    
            guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                completion(.failure(.invalidResponse))
                return
            }
    
            guard let data = data else {
                completion(.failure(.invalidData))
                return
            }
    
            do {
                let users = try JSONDecoder().decode([User].self, from: data)
                completion(.success(users))
            } catch {
                completion(.failure(.invalidData))
            }
        }
        task.resume()
    }
    
    ご覧の通り、ここでたくさんのことが起こっています.デバッグするのはかなり難しいですが、ユーザデータを取得するだけでエラー処理がたくさんあります.ほとんどのプログラマは、非常に反復的で醜い取得プロジェクトのカップルを書く必要がありました.
    ビューコントローラで.Swiftファイルは、テーブルビュー内のデータを表示することを決めたので、我々は1つのデータソースに準拠した.この関数をコールすることを決めたら、次のようになります.
    //MARK: 1. example -> with completion handlers
    private var users = [User]()
    ​
    private func getUsersFirstExample() {
        NetworkManager.shared.fetchUsersFirstExample { [weak self] result in
            guard let weakself = self else { return }
    
            switch result {
            case .success(let users):
                DispatchQueue.main.async {
                    weakself.users = users
                    weakself.tableView.reloadData()
                }
            case .failure(let error):
                print(error)
            }
        }
    }
    

    非同期関数の定義と呼び出し


    さて、ここでは、async/waitを使って関数を書く方法を示します.
    //MARK: fetch users with async/await using Result type
    func fetchUsersSecondExample() async -> Result<[User], NetworkingError> {
        let usersURL = URL(string: Constants.url)
    
        guard let url = usersURL else {
            return .failure(.invalidURL)
        }
    
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            let users = try JSONDecoder().decode([User].self, from: data)
    
            return .success(users)
        }
        catch {
            return .failure(.invalidData)
        }
    }
    
    非同期関数は、実行中に途中で中断することができる特別な種類の関数です.これは同期関数とは逆のもので、これは補完処理を実行し、エラーをスローしたり、決して返しません.
    私たちは2つのキーワードを使っています.
    コードの一部が非同期である場合、コンパイラに指示するために、asyncキーワードを使用します.そして、WAITキーワードで、我々はデータまたはエラーが返されるまで、それが機能を中断するオプションがあると我々のコンパイラに話します;そして、関数がどこでスレッドをブロックさせるかもしれないかを示すために、他の言語と同じように、C .
    迅速なAPIは、urlsessionのように、非同期です.
    しかし、次に、どのように、それはUIKitベースの視点コントローラのような非同期でない文脈の中で、asyncマークされた機能を呼びますか?
    我々がする必要があるのは、非同期クロージャに呼び出しをラップすることです.この関数は、次のように非同期呼び出しを実行できるタスクを作成します.
    //MARK: 2. example -> async/await with Result type
    private func getUsersSecondExample() {
        async {
            let result = await NetworkManager.shared.fetchUsersSecondExample()
    
            switch result {
            case .success(let users):
                DispatchQueue.main.async {
                    self.users = users
                    self.tableView.reloadData()
                }
            case .failure(let error):
                print(error)
            }
        }
    }
    
    結果のTypeはSwift 5.0で導入され、その利点は補完ハンドラを改善することです.
    ASIC/WAITがSwift 5.5ではもちろん導入されるようになりました.
    しかし、結果を格納するための最良の方法であるので、それは役に立たない(上記の例で見ることができるように).
    ここでは、もう一つの例として、結果型を持たないAsync/waitを使用します.
    //MARK: fetch users with async/await third example, without Result type
    func fetchUsersThirdExample() async throws -> [User]{
        let usersURL = URL(string: Constants.url)
        guard let url = usersURL else { return [] }
        let (data, _) = try await URLSession.shared.data(from: url)
        let users = try JSONDecoder().decode([User].self, from: data)
        return users
    }
    
    ViewControllerでのAsync関数の呼び出しSwiftファイル:
    override func viewDidLoad() {
        super.viewDidLoad()
        configureTableView()
        async {
            let users = await getUsersThirdExample()
            guard let users = users else { return }
            self.users = users
            self.tableView.reloadData()
        }
    }
    ​
    //MARK: 3. example -> async/await without Result type
    private func getUsersThirdExample() async -> [User]? {
        do {
            let result = try await NetworkManager.shared.fetchUsersThirdExample()
            return result
        } catch {
            // handle errors
        }
        return nil
    }
    
    上記の例についてのもう一つの本当に良いことは、非同期呼び出しが実行されても、DROFTのデフォルトのエラー処理をdo、try、catchで使うことができます.
    私たちの例の両方で見ることができますように、保持サイクルを避けるために弱い自己キャプチャがありません、そして、私たちがそれを気にしている主な俳優(@mainActor)を持っているので、主な糸の上でUIを更新する必要はありません(主な俳優はSwiftの新しい同時実行パターンを使用しているならば、アクセス可能です).
    そして、ここでは我々の結果です

    結論


    非同期/待機は、迅速な同時通貨オプションの一部ですアップルのSDKSはそれらを大量に利用し始めている.これは、迅速に非同期コードを書くための新しい方法を提供します唯一の欠点は、古いオペレーティングシステムのバージョンとは互換性がなく、まだasync/waitを使っていない他のコードと対話する必要があることです.この記事では、Swiftで非同期プログラミングをよりよく理解するのに役立つことを願っています.
    あなたがこのパターンについてもっと学びたいならば、または迅速な同時性で導入されたすべてについて、アップルの公式ウェブサイトを訪問して、彼らのドキュメンテーションを読んでください.さらに、これらの有用なリンクをチェックアウトできます.
  • Use async/await with URLSession
  • Meet async/await in Swift
  • Swift Evolution Proposal - Async/await (GitHub)

  • Swift Programming language - Concurrency
  • ソースコードに興味があればmy GitHub account .