42
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Swift] iOS開発、API通信のライブラリMoyaのチュートリアル

Last updated at Posted at 2018-07-26

Moyaライブラリについて

このページは下記の英語のページを翻訳したものです。翻訳の許可を頂いてます。

Moya Tutorial for iOS: Getting Started

翻訳中に思ったことは発想がAPIKitのコンセプトに似ている気がしました。
似ていると言ってもAPI通信後のresponseのハンドリングで結果の成功と失敗をenumを使ってハンドリングしている部分なので他にもそういうライブラリがあった場合は申し訳ないです。

Moya Tutorial for iOS: 入門

注記:このチュートリアルではXcode 10とSwift 4.2を使用します。 依存しているライブラリはSwift 4.2ではまだ更新されていませんが問題なく使用できます。 Swift 4.2変換が利用可能であることを伝える一つの警告を無視する必要があります。

美しくパフォーマンスのあるiOSアプリの制作には多くの動きがあります。最も重要な部分の1つは、(現代的なアプリケーションにとって最も重要ではないにしても)ネットワーキングです。iOSデベロッパーとして、URLSessionまたはサードパーティ製のライブラリを使用しているかどうかなど、さまざまな方法でネットワーキングレイヤーを構成することができます。

このチュートリアルでは、**Moya**という名前のサードパーティネットワーキングライブラリについて学びます。Moyaはネットワークサービスとリクエストに対してタイプセーフな構造を作成することを目的としています。

あなたは疑問に思うかもしれません。*"このモヤは何で?私はすでにAlamofireを知っていて愛しています!"*あなたがそれを知らないと愛していないなら、今このテーマに関する素晴らしいチュートリアルをチェックするのはすばらしい時間になるはずです。

さて、MoyaはAlamofireを実際に使っていますが、Moyaはネットワークレイヤーを構築するために別のアプローチを提供しています。 MoyaとAlamofireの関係については、このチュートリアルの後半で詳しく説明します。

このチュートリアルでは、ComicCardというきちんとした小さなアプリを作成します。このアプリでは、**Marvel APIを使用して、特定の週にリリースされた漫画のリストと、カバー画像やその他の興味深い情報をユーザーに表示します。 ユーザーがコミックを選択すると、コミックの情報と画像を含む共有可能なカードの画像が生成され、ユーザーはそれをImgur**のサービスにアップロードして共有することができます。

giphy-13-1.gif

ワオ - 1つのアプリで2つの異なるAPIサービスを使用できますか? 心配しないでください! それは思うほど難しくありません。 始めましょう!

このチュートリアルでは、HTTP APIの基本的な知識を前提としていますが、最小限の知識でこのチュートリアルを簡単に実行できるはずです。しかし、HTTP APIの詳細を知りたい場合は、前述のAlamofireチュートリアルを参照するか、REST APIの基本についてのこの興味深いサイトを参照してください。

入門

このチュートリアルの上部または下部にある「素材をダウンロード」ボタンを使用して、既にMoyaがバンドルされているComicCardスタータープロジェクトをダウンロードします。 プロジェクトファイルではなくComicCards.xcworkspaceを開く - これは重要です。

プロジェクトを開いた状態でMain.storyboardをチェックして、アプリの構造を理解してください:

tutorial_moya1.png

ComicCardsアプリは2つの異なる画面で構成されています:

  • ComicsViewController:コミックのリストをユーザに提示するビューコントローラ。
  • CardViewController:選択されたコミックのカードを作成し、生成されたカードを共有させるビューコントローラ。

プロジェクトをビルドして実行します。 次の画面が表示されます。

tutorial_moya2.png

当然、サーバーからコミックを取り出してアプリケーションに表示することに関連するロジックをまだ実装していないので、エラー画面が表示されます。すぐに必要なコードをすべて追加することになりますが、まずはMoyaについて少し勉強する必要があります。

Moya: What Is It?

What Is Moya?(Moyaって何?)

Moyaはネットワーク要求をカプセル化することに重点を置いています。通常、列挙型(例:enum)を使用してネットワーク要求をカプセル化して、ネットワーク層での作業時にコンパイル時の保証と信頼性を提供します。

AshyのEidolonアプリのためにAsh FurrowさんとOrta Theroxさんによって作られ、すぐに人気を得ました。 今日、それはオープンソースの貢献者の情熱的なコミュニティによって完全に維持されています。

How Is Moya Related to Alamofire? (MoyaはAlamofireとどのように関係していますか?)

このチュートリアルの冒頭で述べたように、MoyaとAlamofireは、Moyaが実際にはネットワーク化を実際に行っていないという事実と密接に関連しています。Alamofireのbattle-tested済みのネットワーキング機能を使用し、Alamofireをさらに抽象化するための追加のabilities、型、概念を提供します。

実際には、Alamofireを使用しています。直接使用する代わりに、Moyaを使用します。MoyaはAlamofireをフードの下で使用します。

スタータープロジェクトのPodfile.lockを見てみると、AlamofireはMoyaの依存関係です。

moya_tutorial3.png

Moya’s Building Blocks(Moyaのビルディングブロック)

Moyaは、コードを書く前に知っておくべきいくつかのユニークな概念とビルディングブロックを紹介しています。 以下のビルディングブロックを使用して、ネットワークチェーン全体を記述します。

tutorial_moya4.png
  • Provider:MoyaのMoyaProviderは、あらゆるネットワークサービスとやり取りするときに作成して使用する主なオブジェクトになります。 これは初期化時にモヤターゲットを取る汎用オブジェクトです。
  • Target:Moyaターゲットは通常、APIサービス全体を記述します。 この場合、MarvelのTargetとImgurのTargetです。これらの各ターゲットは、サービスや可能なエンドポイント、および要求を実行するために各エンドポイントが必要とする情報を記述します。 TargetTypeプロトコルに準拠してターゲットを定義します。
  • Endpoint:Moyaは、self-internal Endpointオブジェクトを使用して、HTTPリクエスト、リクエストボディ、ヘッダーなどのネットワーク要求を実行するために必要な基本情報を記述します。MoyaのMoyaProviderはすべてのターゲットをEndpointに変換します。Endpointは最終的に未処理のURLRequestに変換されます。Endpointは高度にカスタマイズ可能ですが、このチュートリアルでは範囲外です。カスタムマッピングが不要なためです。

基本的な理論のすべてが完成したので、コードを書くときです!

Marvel API – The API of Heroes

Marvel APIは、マーベル自身が作成し維持する世界最大のコミックAPIです。

まず、無料のアカウントを作成します。 すべての設定が完了したら、[開発者アカウント]ページに戻り、新しい公開キーと秘密キーを見つけます。

tutorial_moya5.jpg

両方のキーを手元に置いてください。 数分でそれらを必要とします。

Creating Your First Moya Target

ComicCards Xcodeプロジェクトに戻ります。 プロジェクトナビゲータで、ComicCards/Networkフォルダを右クリックし、New File ...を選択します。新しいSwiftファイルを作成し、Marvel.swiftという名前を付けます。

tutorial_moya6.png

Foundationをインポートした後、次のコードを追加します。

Marvel.swift
import Moya

public enum Marvel {
  // 1
  static private let publicKey = "YOUR PUBLIC KEY"
  static private let privateKey = "YOUR PRIVATE KEY"

  // 2
  case comics
}

使用するAPIサービスを記述する非常に単純な列挙型を作成しました。

  1. これらはMarvelの公開鍵と秘密鍵です。 それらをサービスの定義の横に格納して、サービス設定の一部としてキーに簡単にアクセスできるようにします。 前の手順で生成された実際のキーでプレースホルダを置き換えてください。
  2. comicsという名前の単一のenum case。マーベルのAPIであるGET - /v1/public/comicsでヒットする唯一のエンドポイントを表します。

基本的な列挙が設定されたので、実際にTargetTypeに準拠させてターゲットにするときです。

ファイルの最後に次のコードを追加します(中かっこの後ろ)。

Marvel.swift
extension Marvel: TargetType {
  // 1
  public var baseURL: URL {
    return URL(string: "https://gateway.marvel.com/v1/public")!
  }

  // 2
  public var path: String {
    switch self {
    case .comics: return "/comics"
    }
  }

  // 3
  public var method: Moya.Method {
    switch self {
    case .comics: return .get
    }
  }

  // 4
  public var sampleData: Data {
    return Data()
  }

  // 5
  public var task: Task {
    return .requestPlain // TODO
  }

  // 6
  public var headers: [String: String]? {
    return ["Content-Type": "application/json"]
  }

  // 7
  public var validationType: ValidationType {
    return .successCodes
  }
}

これは大量のコードのように見えるかもしれませんが、単にTargetTypeに準拠するだけです。 これをブレイクダウンしよう:

  1. すべてのターゲット(サービスなど)にはbaseURLが必要です。 Moyaはこれを使用して最終的に正しいEndpointオブジェクトを構築します。
  2. ターゲットのすべてのケースについて、baseURLを基準にして、ヒットしたい正確なpathを定義する必要があります。 コミックのAPIはhttps://gateway.marvel.com/v1/public/comics にあるので、ここでの値は単純に /comics です。
  3. ターゲットのすべてのケースに対して正しいHTTPメソッドを提供する必要があります。 ここで、.getはあなたが望むものです。
  4. sampleDataは、テスト用のmocked/stubbed付きバージョンのAPIを提供するために使用されます。あなたの場合は、1つまたは2つのコミックだけでfakeなresponseを返すことができます。 単体テストを作成すると、Moyaはネットワークに接続する代わりに、この「fake」なresponseを返すことができます。 このチュートリアルの単体テストを行っていないので、空のDataオブジェクトを返します。
  5. taskは、おそらく束の中で最も重要なプロパティです。使用したいすべてのエンドポイントに対してTask列挙ケースを返すことが期待されます。 プレーンリクエスト、データリクエスト、パラメータリクエスト、アップロードリクエストなど、使用できるタスクには多くのオプションがあります。 これは、次のセクションでこれを扱うので、現在は "// TODO"とマークされています。
  6. headersは、ターゲットのすべてのエンドポイントに対して適切なHTTPヘッダーを返す場所です。すべてのMarvel APIエンドポイントはJSONのresponseを返すので、すべてのエンドポイントに対してContent-Type:application/jsonヘッダーを安全に使用できます。
  7. validationTypeは、成功したAPIリクエストの定義を提供するために使用されます。あなたのケースでは、多くのオプションが用意されています。あなたの場合、単純に**.successCodes**を使用します。つまり、HTTPコードが200〜299の場合、要求は成功したとみなされます。

単一のケース(.comics)しか持っていない場合でも、すべてのプロパティでswitch文を使用していることに注意してください。 ターゲットが容易に進化しより多くのエンドポイントを追加できるので、これは一般的なベストプラクティスです。 新しいエンドポイントには、異なるターゲットプロパティーのための独自の値が必要です。

うわー、それは取るべき多くのナレッジだった! Moyaを最も基本的な形で扱うために知っておくべきことのほとんどであるという事実を考えると、あなたは非常に誇りに思うべきです!

あなたの新しいMarvelターゲットに欠けているのは、コード内に残されている「TODO」、つまり返されたTaskだけです。

Authorizing Requests in Marvel’s API (MarvelのAPIでのリクエストの承認)

Marvel APIは、独自の認可スキームを使用します。この認可スキームでは、ユニークなindetifier(timestampなど)、秘密鍵と公開鍵をすべて一緒に連結し、MD5を使用してハッシュします。完全な仕様は、APIリファレンスの「サーバーサイドのアプリケーションの認証」に記載されています。

Marvel.swiftでは、taskを次のように置き換えます。

Marvel.swift
public var task: Task {
  let ts = "\(Date().timeIntervalSince1970)"
  // 1
  let hash = (ts + Marvel.privateKey + Marvel.publicKey).md5
  
  // 2
  let authParams = ["apikey": Marvel.publicKey, "ts": ts, "hash": hash]
  
  switch self {
  case .comics:
    // 3
    return .requestParameters(
      parameters: [
        "format": "comic",
        "formatType": "comic",
        "orderBy": "-onsaleDate",
        "dateDescriptor": "lastWeek",
        "limit": 50] + authParams,
      encoding: URLEncoding.default)
  }
}

あなたのtaskは準備ができています! それは何かと言うと

  1. 上記のように、ランダムなタイムスタンプ、秘密鍵と公開鍵を連結し、次に文字列全体をMD5としてハッシュして、必要なハッシュを作成します。Helpers/String+MD5.swiftにあるmd5ヘルパープロパティを使用しています。
  2. authParamsディクショナリには、必要な認証パラメータが含まれています。apikeyts、およびhashは、それぞれ公開鍵、タイムスタンプ、ハッシュを含みます。
  3. 以前に持っていた**.requestPlainタスクの代わりに、パラメータ付きのHTTP要求を処理する.requestParametersタスクタイプの使用に切り替えます。あなたは、最新のonsaleDateでソートされた与えられた週から最大50件の漫画が必要であることを示すいくつかのパラメータをタスクに提供します。 先ほど作成したauthParams**をパラメータのディクショナリに追加し、残りのリクエストパラメータと共に送信します。

この時点で、あなたの新しいマーベルターゲットは準備ができています! 次に、それを使用するためにComicsViewControllerを更新します。

Using Your Target

ComicsViewController.swiftに移動し、ViewControllerクラスの先頭に次の行を追加します。

ComicsViewController.swift
let provider = MoyaProvider<Marvel>()

前述したように、Moyaターゲットとのやりとりに使用する主なクラスはMoyaProviderです。まず、新しいMarvelターゲットを使用するMoyaProviderのインスタンスを作成します。

次に、**viewDidLoad()**の内部で、次のように置き換えます。

ComicsViewController.swift
state = .error

それと

ComicsViewController.swift
// 1
state = .loading

// 2
provider.request(.comics) { [weak self] result in
  guard let self = self else { return }

  // 3
  switch result {
  case .success(let response):
    do {
      // 4
      print(try response.mapJSON())
    } catch {
      self.state = .error
    }
  case .failure:
    // 5
    self.state = .error
  }
}

新しいコードは次のことを行います:

  1. まず、ビューの状態を**.loading**に設定します。
  2. providerを使用して、.comicsエンドポイントでリクエストを実行します。.comicsenumのケースなので、これは完全にタイプセーフであることに注意してください。したがって、間違ったオプションを間違ってタイプする心配はありません。 ターゲットのすべてのエンドポイントに対して自動完成のケースを取得するという付加価値があります。
  3. クロージャーは、結果を提供します。**.success(Moya.Response)または.failure(Error)**です。
  4. リクエストが成功した場合、MoyaのmapJSONメソッドを使用して、成功したレスポンスをJSONオブジェクトにマップしコンソールに出力します。変換によって例外がスローされた場合は、ビューの状態を**.error**に変更します。
  5. 返されたresultが**.failureの場合は、ビューの状態も.error**に設定します。

アプリをビルドして実行します。 Xcodeデバッグコンソールには、次のようなものが表示されます。

sample.json
{
    attributionHTML = "<a href=\"http://marvel.com\">Data provided by Marvel. \U00a9 2018 MARVEL</a>";
    attributionText = "Data provided by Marvel. \U00a9 2018 MARVEL";
    code = 200;
    copyright = "\U00a9 2018 MARVEL";
    data =     {
        count = 19;
        limit = 50;
        offset = 0;
        results =         (
            {comic object},
            {comic object},
            {comic object},
            ...
        )
}

素晴らしいことに、Moyaと新しいMarvelターゲットを使用して、バックエンドから有効なJSON応答を得ました!

デバッグコンソールに結果が表示されるまで数秒かかることがあります。

tutorial_moya6.jpg

このViewControllerを完成させる最後のステップは、JSONレスポンスを適切なデータモデルにマッピングすることです。あなたのケースでは、あらかじめ設定されたComicのsturctです。

これは、未処理のJSONではなくDecodableにレスポンスをマッピングする別のMoyaレスポンスマッパーを使用するのに最適なタイミングです。

JSONレスポンスの構造は次のようになります。

sample.json
data ->
  results -> 
      [ Array of Comics ]

オブジェクトそれ自体に到達する前に、ネスト(dataresults)の2つのレベルを意味します。 このスタータープロジェクトには、すでにこれをデコードするための適切なDecodableオブジェクトが含まれています。

次のものに置き換えてください:

Sample.swift
print(try response.mapJSON())

を使用して:

Sample.swift
self.state = .ready(try response.map(MarvelResponse<Comic>.self).data.results)

オブジェクトを未処理のJSONレスポンスにマッピングする代わりに、MarvelResponseジェネリックのDecodableジェネリックをComic構造体で取得するマッパーを使用します。これにより、2つのレベルのネストも解析され、data.resultsにアクセスしてコミックの配列にアクセスすることができます。

ビューの状態を**.readyに設定します。関連する値はDecodableマッピングから返されたComic**オブジェクトの配列です。

プロジェクトをビルドして実行します。 最初の画面が完全に機能しているはずです。

tutorial_moya7.png

次に詳細なビューに!

コミックをタップすると、スタータープロジェクトには既にCardViewControllerを表示し、選択したコミックをそれに渡すコードがあります。しかし、コミックをタップすると、漫画の詳細がない空のカードしか表示されないことに気付くかもしれません。 それに対応しましょう!

CardViewController.swiftに切り替え、**layoutCard(comic :)**メソッドを見つけます。 このメソッドの中に、以下を追加します。

CardViewController.swift
// 1
lblTitle.text = comic.title
lblDesc.text = comic.description ?? "Not available"

// 2
if comic.characters.items.isEmpty {
  lblChars.text = "No characters"
} else {
  lblChars.text = comic.characters.items
                       .map { $0.name }
                       .joined(separator: ", ")
}

// 3
lblDate.text = dateFormatter.string(from: comic.onsaleDate)

// 4
image.kf.setImage(with: comic.thumbnail.url)

このコードは、提供されたComic構造体からの情報で画面を更新します。

  1. 漫画のタイトルと漫画の説明を設定する。
  2. 漫画の文字のリストをセットするか、文字がない場合は「No characters」をセットします。
  3. あらかじめ設定されたDateFormatterを使用して、コミックの**「販売開始日」**をセットする。
  4. Kingfisherを使って漫画の画像を読み込む - ウェブ画像を読み込むためのサードパーティ製で素晴らしいライブラリです。

アプリをビルドして実行し、リストの漫画の1つをタップすると美しい情報カードが表示されます。

tutorial_moya8.png

追加する機能がもう2つあります:Imgurにカードをアップロードすることとカードを削除させることです。

Imgur – Sharing With Friends! (Imgur - 友達とシェア!)

このため、Imgurという別のMoyaターゲットを作成します。このターゲットは、アップロード用と削除用の2つの異なるエンドポイント(イメージ処理用)と対話できるようにします。

Marvel APIと同様に、Imgurで**無料アカウントを登録**する必要があります。

その後、Imgurアプリケーションを作成する必要があります。ここでOAuthを使用しないため、コールバックに任意のフェイクのURLを使用するかもしれません。 ** OAuth 2認証をコールバックURLなしで **選択することもできます。

tutorial_moya9.png

フォームを提出すると、Imgurは新しいImgurのClientIDClient secretを提示します。 次のステップのためにこれらを保存します。

Creating the Imgur Target (Imgurターゲットの作成)

ComicCards/Networkフォルダを右クリックして、**New File ...**を選択し、新しいSwiftファイルを作成し、Imgur.swiftという名前を付けます。

実装して使用するImgurエンドポイントを定義するには、次のコードを追加します。

Imgur.swift
import UIKit
import Moya

public enum Imgur {
  // 1
  static private let clientId = "YOUR CLIENT ID"

  // 2
  case upload(UIImage)
  case delete(String)
}

Marvel APIと同様に、

  1. Imgur Client IDをclientIdに格納します。 これを前の手順で生成したクライアントIDに置き換えてください(secretは必要ありません)。
  2. 使用する2つのエンドポイント、アップロード(イメージのアップロード)、および**削除(以前にアップロードしたイメージのハッシュを取り、Imgurから削除)**を定義します。 これらはImgur APIでPOST /imageDELETE /image/{imageDeleteHash}として表されます。

次に、TargetTypeに準拠します。 新しいenumのすぐ下に次のコードを追加します。

Imgur.swift
extension Imgur: TargetType {
  // 1
  public var baseURL: URL {
    return URL(string: "https://api.imgur.com/3")!
  }

  // 2
  public var path: String {
    switch self {
    case .upload: return "/image"
    case .delete(let deletehash): return "/image/\(deletehash)"
    }
  }

  // 3
  public var method: Moya.Method {
    switch self {
    case .upload: return .post
    case .delete: return .delete
    }
  }

  // 4
  public var sampleData: Data {
    return Data()
  }

  // 5
  public var task: Task {
    switch self {
    case .upload(let image):
      let imageData = image.jpegData(compressionQuality: 1.0)!

      return .uploadMultipart([MultipartFormData(provider: .data(imageData),
                                                 name: "image",
                                                 fileName: "card.jpg",
                                                 mimeType: "image/jpg")])
    case .delete:
      return .requestPlain
    }
  }

  // 6
  public var headers: [String: String]? {
    return [
      "Authorization": "Client-ID \(Imgur.clientId)",
      "Content-Type": "application/json"
    ]
  }

  // 7
  public var validationType: ValidationType {
    return .successCodes
  }
}

これは今あなたによく知られているはずです。 新しいImgurターゲットの7つのプロトコルプロパティを見てみましょう。

  1. Imgur APIのbaseURLhttps://api.imgur.com/3 に設定されています。
  2. ケースに基づいて適切なエンドポイントpathを返します。.uploadなら /imageを、.deleteなら /image/{deletehash}を返します。
  3. methodは、caseにも基づいて異なります。.uploadなら post を、.deleteなら.deleteを返します。
  4. 前と同じように、sampleDataは空のData構造体を返します。
  5. taskは面白いところです。すべてのエンドポイントに対して異なるタスクを返します。 .deleteの場合は、単純なDELETE要求なので、パラメータやコンテンツは必要ありませんが、.uploadの場合はもう少し作業が必要です。ファイルをアップロードするには、MultipartFormData構造体の配列をとる**.uploadMultiparttask型を使用します。次に、適切なimage data、フィールド名、ファイル名、およびイメージMIMEタイプを使用してMultipartFormData**のインスタンスを作成します。
  6. Marvel APIと同様に、headersプロパティはContent-Type:application / jsonヘッダーと追加のヘッダーを返します。Imgur APIはヘッダー認証を使用するため、すべてのリクエストのヘッダーにクライアントIDを**Authorization:Client-ID(あなたのクライアントID)**の形式で提供する必要があります。
  7. .validationTypeは、200〜299の間の任意のステータスコードに対して、前と同じです。

あなたのImgurターゲットが完成しました! これで、ComicCardsアプリのMoya関連のコードは終了です。

tutorial_moya_.jpg

最後のステップは、新しく作成されたMoyaターゲットを使用するためにCardViewControllerを完成させることです。

Wrapping Up CardViewController

CardViewController.swiftに戻って、CardViewControllerクラスのはじめに、comicプロパティの下に次の行を追加します。

CardViewController.swift
private let provider = MoyaProvider<Imgur>()
private var uploadResult: UploadResult?

前と同じように、Imgurターゲットで今回はMoyaProviderインスタンスを作成します。また、uploadResultを定義します。これはアップロードの結果を保存するために使用するOptionalのuploadResultプロパティです。イメージを削除するときに必要になります。

実装するには、**uploadCard()deleteCard()**の2つのメソッドがあります。

**uploadCard()**の最後に次のコードを追加します:

CardViewController.swift
// 1
let card = snapCard()

// 2
provider.request(.upload(card),
  // 3
  callbackQueue: DispatchQueue.main,
  progress: { [weak self] progress in
    // 4
    self?.progressBar.setProgress(Float(progress.progress), animated: true)
  },
  completion: { [weak self] response in
    guard let self = self else { return }
    
    // 5
    UIView.animate(withDuration: 0.15) {
      self.viewUpload.alpha = 0.0
      self.btnShare.alpha = 0.0
    }
    
    // 6
    switch response {
    case .success(let result):
      do {
        let upload = try result.map(ImgurResponse<UploadResult>.self)
        
        self.uploadResult = upload.data
        self.btnDelete.alpha = 1.0
        
        self.presentShare(image: card, url: upload.data.link)
      } catch {
        self.presentError()
      }
    case .failure:
      self.presentError()
    }
})

コードのこの大きな部分は間違いなくいくつかの説明を必要としますが、心配しないでください - そのほとんどは比較的よく知られているはずです。

  1. snapCard()というヘルパーメソッドを使用して、提示されたカードから画面上にUIImageを生成します。
  2. Marvel APIと同様に、providerを使用して、カード画像の関連値とともにuploadエンドポイントを呼び出します。
  3. callbackQueueを使用すると、次回のコールバックでアップロードの進行状況の更新を受け取るqueueを提供できます。メインスレッドで進行状況の更新が確実に行われるように、メインのDispatchQueueを指定します。
  4. Imgurに画像がアップロードされるときに呼び出される進捗クロージャを定義します。プログレスバーの進行状況が設定され、callbackQueueで提供されるメインのDispatchQueueで呼び出されます。
  5. requestが完了すると、アップロードビューと共有ボタンがフェードアウトします。
  6. 前と同じように、結果の成功と失敗のオプションを処理します。成功した場合は、レスポンスをImgurResponseにマップし、次にマップされたレスポンスを前に定義したインスタンスプロパティに格納します。このプロパティは、後で**deleteCard()**メソッドを終了するときに使用します。アップロードの結果を保存したら、presentShareメソッドを起動します。このメソッドは、アップロードされた画像のURLと画像自体に適切な共有アラートを表示します。 失敗すると、**presentError()**メソッドがトリガーされます。

そして、その日の最後のコードについてです。次のコードを**deleteCard()**の中に追加してください:

CardViewController.swift
// 1
guard let uploadResult = uploadResult else { return }
btnDelete.isEnabled = false

// 2
provider.request(.delete(uploadResult.deletehash)) { [weak self] response in
  guard let self = self else { return }

  let message: String

  // 3
  switch response {
  case .success:
    message = "Deleted successfully!"
    self.btnDelete.alpha = 0.0
  case .failure:
    message = "Failed deleting card! Try again later."
    self.btnDelete.isEnabled = true
  }

  let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert)
  alert.addAction(UIAlertAction(title: "Done", style: .cancel))

  self.present(alert, animated: true, completion: nil)
}

このメソッドはかなりシンプルで、次のように動作します。

  1. uploadResultが利用可能であることを確認し、削除ボタンを無効にして、ユーザーが再度それをタップしないようにします。
  2. Imgur providerを使用して、アップロード結果のdeletehashに関連付けられた値でdeleteエンドポイントを呼び出します。 このハッシュは、アップロードされたイメージを一意に(uniquely)識別します。
  3. deleteの成功または失敗の場合、適切なメッセージが表示されます。

以上です! 最後に1回アプリをビルドして実行します。 漫画を選び、イメージをImgurに共有してください。作業が完了したら、**[Delete from Imgur]**ボタンをタップして削除できます。

あなたは気づいたかもしれないが、あなたがCardViewControllerにいる限り、アップロードされた画像を削除できることです。そのまま残すと、ViewControllerのuploadResultはクリアされ、deletehashは失われます。 さまざまなセッションで生成されたイメージのハッシュを維持することは、あなたが取り組むべきかもしれない素晴らしいチャレンジです。

Taking Moya to the Next Level (Moyaの次のレベルについて)

Moyaは非常に多用途なネットワーキングライブラリであり、このチュートリアルで扱う数多くの機能を追加していますが、

  1. Reactive Extensions: Moyaは、RxSwiftReactiveSwift用のMoya(RxMoyaReactiveMoya)に2種類の優れたReactive Additionsを提供し、維持しています。
  2. Plugin:Moyaでは、プラグインという名前の作品を作成して、リクエストやレスポンスを修正したり、副作用を実行したりすることができます。 たとえば、requestとresponseのロギングやネットワークリクエストの実行中にネットワークアクティビティインジケータを自動的に表示する場合に便利です。
  3. Testing:前述のように、すべてのTargetTypeにはsampleDataプロパティがあり、エンドポイントに対してスタブ付きreponseを提供できます。MoyaProviderを作成するときに、StubClosureを指定することができます。これは、Moyaにスタブ付きresponseまたは実際のresponseを返すかどうかを定義します(デフォルト)。 これについては、Moyaの**テストドキュメント**を参照してください。
  4. ハーヴェイ:スタブのreponseといえば、Moyaの背後にあるチームのなかには、ハーヴェイと呼ばれる別々のフレームワークを開発してネットワークレスポンスを簡単に嘲笑するものがあります。それはまだ初期の開発ですが、私は非常にこのプロジェクトに従うことをお勧めします。
42
44
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?