Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Alamofireを使ったメソッドで返り値を取得する

More than 1 year has passed since last update.

APIからjsonを取得しようと思った際に、なんども使うことになりそうなので、APIを叩く関数を作り、それを呼び出すようにしようと思いました。
調べたらswiftでjsonを扱うライブラリはAlamofireが有名らしいのでそれを使うことにしました。

環境

  • MacOS Mojave 10.14.2
  • Xcode10.1
  • Swift 4.2.1

最初にやろうとしたこと

まず最初に、単純に関数内でapiを叩いてその値を返すようにしようとおもい下記のように書いてみました。

import Alamofire
import SwiftyJSON

func getJsonData(url: String) -> JSON {
    var json = JSON()
    Alamofire.request(url).responseJSON { response in
        print("in response") 
        switch (response).result {
        case .success(let Value):
            print("success")
            json = JSON(Value)
        case .failure(let Error):
            print(Error)
            json = JSON(Error)
        }
    }
    return json
}

URL文字列を取得して、JSONを返すことをしようとしています。これを使いたいところで呼び出してみたところ、

let jsonData = HandleDataUtil().getJsonData(url: requestURL)   // HandleDataUtilは上記関数を書いてるクラス
print(jsonData)

コンソールには下記のように表示されました。(全部の修正完了後に思い出し思い出し書いてるのでちょっと違うかも...)

in response
success
{

}

通信は成功してるけど、データが返ってきていません。レスポンスが返って来る前に関数の処理を抜けてしまっているようです。
どうすればいいのか調べていたら、参考1を見つけました。

つまりは、

  • { response in ...} の部分は完了ハンドラとして渡される
  • その完了ハンドラが渡されるのは通信完了後
  • しかし、return jsonが実行されるのは通信完了前

ということみたいです。つまり上記でも言った「レスポンス返って来る前にメソッドを抜けてる」ってことです。

どうするか

対処法は

  • 自分で定義したメソッドも完了ハンドラパターンにする

つまりは

  • 返り値と受け取りたい型を引数とするクロージャ型をメソッドの引数に追加
  • Alamofireの完了ハンドラのなかで自前の完了ハンドラを呼ぶ

ことで解決できます。

最終的に下記のようなコードで実現できました。

func getJsonData(url: String, completion: @escaping (JSON) -> Void) {
    Alamofire.request(url).responseJSON { response in
        print("in response")
        switch (response).result {
        case .success(let Value):
            print("success")
            completion(JSON(Value))
        case .failure(let Error):
            print(Error)
            completion(JSON(Error))
        }
    }
}

呼び出し側は

var jsonData = JSON()
HandleDataUtil().getJsonData(url: requestURL) { json in
    jsonData = json
    print(jsonData)
}

となります。なんか、最終的にやりたいことと違くなってしまった・・・。

結論

ここまできてなんですが、最終的に思ったのが「メソッドにする価値がないな」です。理由は

  1. 成功した場合、失敗した場合のハンドリングができない
  2. 記述量に大差がない。結局クロージャを使ってるので、これならAlamofireベタ書きと大差ない
  3. むしろAlamofireそのまま書いた方が処理の流れが見やすい。

そもそもAlamofire自体、非同期通信をSwiftで簡単にかけるようにしてくれるライブラリですから、そのまま使えばよかったんだなと反省してます。

参考

  1. Alamofireでのリクエスト結果を返り値にしたい - スタック・オーバーフロー
Rino-T
アプリケーションプログラマ。仕事ではScalaとTypescriptを良く書きます。Scalaは好きだけど、Typescriptは少し苦手。クラウドはAWSを良く使います。個人開発でFlutterを利用したモバイルアプリ開発もたまに。関数型言語が好き。最近はちょっとしたことやる時にAWS SAM(LambdaのRunTimeはPython)を使うようになりました。
http://doratai.hatenablog.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away