iPhone
 Computer >> コンピューター >  >> スマートフォン >> iPhone

Swift で API 呼び出しを行う方法

iOS 開発者を目指すなら、知っておくべき基本的なスキルがいくつかあります。まず、テーブル ビューの作成に慣れることが重要です。次に、これらのテーブル ビューにデータを入力する方法を知っておく必要があります。第 3 に、API からデータをフェッチし、このデータをテーブル ビューで使用できるとよいでしょう。

3 番目のポイントは、この記事で取り上げるものです。 Codable の導入以来 Swift 4 では、API 呼び出しがはるかに簡単になります。以前は、ほとんどの人が Alamofire や SwiftyJson などのポッドを使用していました (その方法については、こちらを参照してください)。現在、Swift の方法はすぐに使用できるようになっているため、ポッドをダウンロードする理由はありません。

API 呼び出しを行うためによく使用される構成要素をいくつか見ていきましょう。これらの概念は、API 呼び出しを行う方法を理解する上で重要な部分であるため、最初に説明します。

  • 完了ハンドラ
  • URLSession
  • DispatchQueue
  • 周期を維持

最後にすべてをまとめます。このプロジェクトの構築には、オープン ソースの Star Wars API を使用します。私の完全なプロジェクト コードは GitHub で見ることができます。

免責事項:私はコーディングは初めてで、ほとんど独学です。いくつかの概念を誤って伝えていたら申し訳ありません.

完了ハンドラ

Swift で API 呼び出しを行う方法
かわいそうなフィービー

フレンズのエピソードで、フィービーが顧客サービスと話すのを何日も電話に釘付けで待っていたエピソードを覚えていますか?その電話の冒頭で、ピップという素敵な人がこう言ったと想像してみてください。あなたのために。"それほど面白くはありませんが、Pip は Pheobe の完了ハンドラーになることを申し出ています。

関数の完了に時間がかかることがわかっている場合は、関数で完了ハンドラーを使用します。どれくらいの期間かわからないので、人生が終わるのを待って一時停止したくありません。それで、ピップが答えを出す準備ができたら、あなたの肩をたたくようにピップに頼みます。そうすれば、自分の生活を送り、用事を済ませ、本を読み、テレビを見ることができます。ピップがあなたの肩をたたいて答えたら、彼女の答えを受け取って使うことができます。

これは、API 呼び出しで起こることです。 URL 要求をサーバーに送信して、データを要求します。サーバーがデータをすばやく返すことを望んでいますが、どれくらいの時間がかかるかわかりません。サーバーがデータを提供するまでユーザーを辛抱強く待たせる代わりに、完了ハンドラーを使用します。これは、アプリをオフにして、ページの残りの読み込みなど、他のことを行うように指示できることを意味します。

必要な情報が得られたら、アプリの肩をタップするように完了ハンドラーに指示します。その情報が何であるかを指定できます。そうすれば、アプリが肩を叩かれたときに、完了ハンドラーから情報を取得して、何かを行うことができます。通常、テーブル ビューをリロードして、データがユーザーに表示されるようにします。

完了ハンドラがどのように見えるかの例を次に示します。最初の例は、API 呼び出し自体の設定です:

func fetchFilms(completionHandler: @escaping ([Film]) -> Void) {
  // Setup the variable lotsOfFilms
  var lotsOfFilms: [Film]
  
  // Call the API with some code
  
  // Using data from the API, assign a value to lotsOfFilms  
  
  // Give the completion handler the variable, lotsOfFilms
  completionHandler(lotsOfFilms)
}
完了ハンドラを使用する関数

ここで、関数 fetchFilms を呼び出します。 .注意事項:

  • completionHandler を参照する必要はありません 関数を呼び出すとき。 completionHandler を参照したときのみ 関数宣言内にあります。
  • 完了ハンドラは、使用するデータを返します。上で書いた関数に基づいて、[Film] 型のデータが期待されることがわかっています。 .データを参照できるように、データに名前を付ける必要があります。以下では films という名前を使用しています 、しかしそれは randomData かもしれません 、または私が望む他の変数名.

コードは次のようになります:

fetchFilms() { (films) in
  // Do something with the data the completion handler returns 
  print(films)
}
完了ハンドラを持つ関数の実装

URL セッション

URLSession チームのマネージャーのようなものです。マネージャーは自分で何もしません。彼女の仕事は、チームのメンバーと仕事を分かち合うことであり、彼らは仕事を成し遂げます。彼女のチームは dataTasks です .データが必要になるたびに、上司に連絡して URLSession.shared.dataTask を使用します .

dataTask を与えることができます 目標を達成するのに役立つさまざまな種類の情報。 dataTask に情報を提供する を初期化と呼びます。私は dataTasks をイニシャライズします URL付き。 dataTasks 初期化の一部として完了ハンドラも使用します。以下に例を示します:

let url = URL(string: "https://www.swapi.co/api/films")

let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in 
  // your code here
})

task.resume()
URLSession を使用してデータを取得する方法

dataTasks 完了ハンドラを使用し、常に同じタイプの情報を返します:dataresponse そして error . (data, res, err) のように、これらのデータ型に別の名前を付けることができます または (someData, someResponse, someError) .慣例として、新しい変数名で乱暴になるのではなく、明白なものに固執するのが最善です.

error から始めましょう . dataTask の場合 error を返します 、あなたはそれを前もって知りたいと思うでしょう。これは、エラーを適切に処理するようにコードを指示できることを意味します。また、データを返すときにエラーが発生するため、わざわざデータを読み取って何かを実行しようとする必要がないことも意味します。

以下では、エラーをコンソールに出力して関数を終了するだけで、エラーを処理しています。必要に応じて、エラーを処理する方法は他にもたくさんあります。このデータがアプリにとってどれほど基本的なものかを考えてみてください。たとえば、バンキング アプリがあり、この API 呼び出しでユーザーに残高が表示される場合、ユーザーに「申し訳ありませんが、現在問題が発生しています。お試しください。後でもう一度。"

if let error = error {
  print("Error accessing swapi.co: /(error)")
  return
}
エラーを処理する

次にレスポンスを見てみます。レスポンスを httpResponse にキャストできます .そうすれば、ステータス コードを見て、コードに基づいていくつかの決定を下すことができます。たとえば、ステータス コードが 404 の場合、ページが見つからなかったことがわかります。

以下のコードは guard を使用しています 2 つのものが存在することを確認します。両方が存在する場合、コードは guard の後の次のステートメントに進むことができます 句。いずれかのステートメントが失敗した場合、関数を終了します。これは guard の典型的な使用例です 句。ガード句の後のコードは、ハッピー デイズ フロー (つまり、エラーのない簡単なフロー) であることが期待されます。

  guard let httpResponse = response as? HTTPURLResponse,
            (200...299).contains(httpResponse.statusCode) else {
    print("Error with the response, unexpected status code: \(response)")
    return
  }

最後に、データ自体を処理します。 error の完了ハンドラを使用していないことに注意してください。 または response .これは、完了ハンドラーが API からのデータを待機しているためです。コードのデータ部分に到達しない場合、ハンドラーを呼び出す必要はありません。

データには JSONDecoder を使用しています 良い方法でデータを解析します。これはかなり気の利いたものですが、モデルを確立する必要があります。私たちのモデルは FilmSummary と呼ばれています . JSONDecoder の場合 を初めて使用する場合は、オンラインで使用方法と Codable の使用方法を確認してください。 . Swift 3 の時代に比べて、Swift 4 以降では非常にシンプルです。

以下のコードでは、最初にデータが存在することを確認しています。エラーや奇妙な HTTP 応答がないため、存在するはずです。次に、受け取ったデータを期待どおりに解析できることを確認します。可能であれば、映画の要約を完了ハンドラに返します。 API から返されるデータがない場合に備えて、空の配列のフォールバック プランがあります。

if let data = data,
        let filmSummary = try? JSONDecoder().decode(FilmSummary.self, from: data) {
        completionHandler(filmSummary.results ?? [])
      }

したがって、API 呼び出しの完全なコードは次のようになります:

func fetchFilms(completionHandler: @escaping ([Film]) -> Void) {
    let url = URL(string: domainUrlString + "films/")!

    let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
      if let error = error {
        print("Error with fetching films: \(error)")
        return
      }
      
      guard let httpResponse = response as? HTTPURLResponse,
            (200...299).contains(httpResponse.statusCode) else {
        print("Error with the response, unexpected status code: \(response)")
        return
      }

      if let data = data,
        let filmSummary = try? JSONDecoder().decode(FilmSummary.self, from: data) {
        completionHandler(filmSummary.results ?? [])
      }
    })
    task.resume()
  }

保持サイクル

注:私は保持サイクルを理解するのに非常に慣れていません!私がオンラインで調べた内容の要点は次のとおりです。

保持サイクルは、メモリ管理のために理解することが重要です。基本的に、アプリが不要になったメモリのビットをクリーンアップする必要があります。これにより、アプリのパフォーマンスが向上すると思います。

これを自動的に行うのに Swift が役立つ方法はたくさんあります。ただし、保持サイクルを誤ってアプリにコード化してしまう可能性がある多くの方法があります。保持サイクルとは、アプリが特定のコードのメモリを常に保持することを意味します。通常、相互に強いポインタを持つ 2 つのものがある場合に発生します。

これを回避するために、人々はよく weak を使用します .コードの片側が weak の場合 、保持サイクルがなく、アプリはメモリを解放できます。

この目的のために、一般的なパターンは [weak self] を使用することです APIを呼び出すとき。これにより、完了ハンドラーが何らかのコードを返すと、アプリはメモリを解放できるようになります。

fetchFilms { [weak self] (films) in
  // code in here
}

ディスパッチキュー

Xcode は、異なるスレッドを使用してコードを並行して実行します。複数のスレッドの利点は、次の処理に移る前に、1 つの処理が完了するのを待つ必要がないことを意味します。ここで完了ハンドラへのリンクを確認できることを願っています。

これらのスレッドは、ディスパッチ キューとも呼ばれているようです。 API 呼び出しは 1 つのキュー (通常はバックグラウンドのキュー) で処理されます。 API 呼び出しからデータを取得したら、ほとんどの場合、そのデータをユーザーに表示したいと思うでしょう。これは、テーブル ビューを更新する必要があることを意味します。

テーブル ビューは UI の一部であり、すべての UI 操作はメイン ディスパッチ キューで行う必要があります。これは、通常は viewDidLoad の一部として、View Controller ファイルのどこかにあることを意味します。 関数を使用するには、テーブル ビューを更新するように指示するコードが少し必要です。

API からの新しいデータがある場合にのみ、テーブル ビューを更新する必要があります。これは、完了ハンドラーを使用して肩をたたき、その API 呼び出しがいつ終了したかを知らせることを意味します。テーブルを更新する前に、そのタップまで待ちます。

コードは次のようになります:

fetchFilms { [weak self] (films) in
  self.films = films

  // Reload the table view using the main dispatch queue
  DispatchQueue.main.async {
    tableView.reloadData()
  }
}

viewDidLoad と viewDidAppear

最後に、fetchfilms を呼び出す場所を決める必要があります。 関数。 APIからのデータを使用するView Controller内にあります。この API 呼び出しを実行できる明らかな場所が 2 つあります。 1つは viewDidLoad の中にあります もう 1 つは viewDidAppear 内にあります。 .

これらは、アプリの 2 つの異なる状態です。私の理解は viewDidLoad です そのビューをフォアグラウンドで初めてロードしたときに呼び出されます。 viewDidAppear 戻るボタンを押してビューに戻ったときなど、そのビューに戻るたびに呼び出されます。

ユーザーがそのビューに移動する時間とそこから移動する時間の間にデータが変更されることが予想される場合は、API 呼び出しを viewDidAppear に配置することをお勧めします。 .ただし、ほぼすべてのアプリで viewDidLoad だと思います 十分なものです。 Apple は viewDidAppear を推奨しています すべての API 呼び出しに適用されますが、それはやり過ぎのように思えます。必要な API 呼び出しをさらに多く行うため、アプリのパフォーマンスが低下すると思います。

すべてのステップを組み合わせる

まず、API を呼び出す関数を記述します。上記では、これは fetchFilms です .これには、関心のあるデータを返す完了ハンドラーがあります。私の例では、完了ハンドラーはフィルムの配列を返します。

2 番目:ビュー コントローラーでこの関数を呼び出します。 API からのデータに基づいてビューを更新するため、ここでこれを行います。この例では、API がデータを返したら、テーブル ビューを更新しています。

3 番目:ビュー コントローラー内で関数を呼び出す場所を決定します。私の例では、viewDidLoad で呼び出します。 .

4 番目:API からのデータをどうするかを決定します。この例では、テーブル ビューを更新しています。

NetworkManager.swift 内 (この関数は、必要に応じてビュー コントローラーで定義できますが、MVVM パターンを使用しています)。

func fetchFilms(completionHandler: @escaping ([Film]) -> Void) {
    let url = URL(string: domainUrlString + "films/")!

    let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
      if let error = error {
        print("Error with fetching films: \(error)")
        return
      }
      
      guard let httpResponse = response as? HTTPURLResponse,
            (200...299).contains(httpResponse.statusCode) else {
        print("Error with the response, unexpected status code: \(response)")
        return
      }

      if let data = data,
        let filmSummary = try? JSONDecoder().decode(FilmSummary.self, from: data) {
        completionHandler(filmSummary.results ?? [])
      }
    })
    task.resume()
  }

FilmsViewController.swift 内 :

final class FilmsViewController: UIViewController {
  private var films: [Film]?

  override func viewDidLoad() {
    super.viewDidLoad()
    
    NetworkManager().fetchFilms { [weak self] (films) in
      self?.films = films
      DispatchQueue.main.async {
        self?.tableView.reloadData()
      }
    }
  }
  
  // other code for the view controller
}

おやおや、やった!いつもご利用いただきありがとうございます。


  1. 削除されたファイルを Mac で復元できないようにする方法

    テクノロジーの進歩に伴い、セキュリティは最大の懸念事項の 1 つです。 Windows コンピューターでも Mac コンピューターでも、高度なサイバー攻撃、個人情報の盗難、およびマルウェアに関しては、どのデバイスにもチャンスはありません。そのため、コンピュータ上のデータを安全に保つことは、各自の責任です。 古いデバイスを販売する前に、ハード ドライブからデータを完全に消去する必要がある場合があります。ファイルをゴミ箱にドラッグしてゴミ箱を空にしても、ファイルが完全に削除または削除されるわけではありません。 Mac のファイル ディレクトリからファイルを削除するだけです。ファイルは、適切な回復ツ

  2. バックアップ データを価値のあるものにする方法

    データのバックアップは、個人と専門家が同等に必要とするものです。私たちは皆、クラウド、外付けドライブ、SD カードにデータをバックアップしています。私たちの中には、データを保存するために他の人よりも多くのスペースが必要な場合があります。同じファイルの多くのコピーをデバイスに保存し、同じことがバックアップにも続くことがよくあります。これはストレージスペースの無駄遣いですが、それが解決策を提供する理由です.このブログ投稿は、バックアップ データを価値のあるものにする方法を理解するのに役立つ方法で構成されています。 重複データという最も一般的な問題から始めましょう。バックアップは、オーディオ、