質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.58%

APIとの通信で取得したデータをスマホUI上に表示させたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,420

score 28

前提・実現したいこと

Swiftで栄養管理アプリを作っています。
処理の流れとしては下記の通りで、今回3のところで行き詰まっています。

  1. カメラでバーコード番号読み取り
  2. バーコード番号をもとにAPIから製品IDを取得
  3. 製品IDをもとにAPIから栄養パラメータを取得
  4. 画面遷移
  5. 4と同時に、3の栄養パラメータをもとにライブラリでグラフを作成

発生している問題・エラーメッセージ

Alamofire(APIとの通信)内では栄養パラメータのひとつを取得できているのですが、
Alamofire外で同じパラメータを表示させようとすると "nil" となってしまいます。

Alamofire外でvitamin_c:nil
Alamofire内でvitamin_c:Optional("10")

また、投稿内容から少しずれるかもしれませんが、
Alamofire内においても値(10)のみ取得したいです。
Optional("")が付随してしまうのはAlamofireの仕様上やむを得ないのでしょうか。
そうであれば文字列変換処理でOptional("")の部分を削除するようにします。

該当のソースコード

public class nutritionDisplayViewController: UIViewController, ChartViewDelegate {

    @IBOutlet weak var barChartView: BarChartView!

    var nutritions: [[String: String?]] = [] //APIとの通信に用いるパラメータ

    //@IBOutlet weak var idLabel: UILabel!
    override public func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        //グラフ作成ライブラリChartsを用いたグラフ作成処理
        setChart(parameter, values: unitsSold)
        //省略
    }

    //カメラで読み取ったバーコード番号を投げて製品特有のAPI独自ID(food_id)を取得する関数
    public func foodFindIdForBarcode(scannedBarcode:String) {

        //省略
        foodGet(food_id)
    }

    // 製品特有のAPI独自IDを投げて栄養パラメータを取得する関数
    public func foodGet(fid:String) {

        let URL = "http://platform.fatsecret.com/rest/server.api"
        var parameters = [String: String]()

        parameters["format"] = "json"
        parameters["food_id"] = fid //製品特有のAPI独自ID

        parameters["method"] = "food.get"

        //OAuth関連のパラメータ設定
        //省略

        var vitamin_c: String?

        Alamofire.request(.GET, URL, parameters: parameters)
            .responseJSON { response in
                guard let object = response.result.value else {
                    return
                }
                let json = JSON(object)
                json.forEach { (_, json) in
                    let nutrition: [String: String?] =
                        ["food_id": json["food_id"]["value"].string,
                         "vitamin_c": json["food"]["servings"]["serving"]["vitamin_c"].string
                    ]
                    self.nutritions.append(nutrition)
                }

                vitamin_c = json["food"]["servings"]["serving"]["vitamin_c"].string!

                print("Alamofire内でvitamin_c:\(vitamin_c)")
        }
        print("Alamofire外でvitamin_c:\(vitamin_c)")
    }

    override public func viewDidAppear(animated: Bool) {

    }

    /*------- Charts -------*/
    func setChart(dataPoints: [String], values: [Double]) {
        //省略
    }

    /*------- OAuth --------*/
    public func oauthSignatureForMethod(method: String, url: NSURL, parameters: Dictionary<String, String>) -> String {
    //省略
    }
}

試したこと

  • Alamofire内でグラフを作成しようと試みましたが、画面遷移の都合上できないことに気づき諦めました。
  • appDelegateに該当のパラメータを一時保存する形を試みましたが、やはり" nil "となってしまいます。

補足情報(言語/FW/ツール等のバージョンなど)

利用したライブラリとバージョン情報

Alamofire:3.4
Charts:2.2.5
SwiftyJSON


宜しくお願いします!

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

Alamofire.request(.GET, URL, parameters: parameters)
    (※省略)
    print("Alamofire内でvitamin_c:\(vitamin_c)")
}
②print("Alamofire外でvitamin_c:\(vitamin_c)")


今回の書き方の場合だと①の処理を実行したあと通信完了を待たずに、
②の処理を行っているためnilが返ってきていると思われます。

通信完了後にそのデータをつかって処理を行いたい場合は
print("Alamofire内でvitamin_c:\(vitamin_c)")の場所に処理を記載する必要があると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/21 13:33

    早速のご回答ありがとうございます!
    やはりその場所に記載しないといけないのですね。
    そうすると別の問題が生まれてしまうのですが、知識不足で解決できず、そちらについては別途質問を投稿させていただきます。

    ただ、通信完了云々というところが恥ずかしながら理解できていません。
    Alamofire.request()のあとの処理であれば、すでに通信は完了していると思いますが、なぜ②の箇所では通信が完了していないのでしょうか?
    逆に、素人目線ですがAlamofire.request()内だと通信中であるように思えますが、なぜprint("Alamofire内でvitamin_c:\(vitamin_c)")の場所が通信完了後となるのでしょうか?

    キャンセル

  • 2016/09/21 13:52

    Alamofireは非同期通信を行うためのフレームワークです。
    非同期通信はご存知かもしれませんが、
    「ネットワークなどでつながれているコンピュータ間で、
    送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式。」

    なので「Alamofire.request()」という処理を別のスレッドで処理することで、
    メインスレッドでの処理を停止させずに実行できるということです。

    なので今回だと「Alamofire内のprint」はその別のスレッド上で基本的に順番に。
    「Alamofire外のprint」はUIなどを動かしているメインスレッドで処理するため上記のような動作になります。

    また通信中という表現ですが「.responseJSON { response in」
    ここ以降が通信が完了した後、
    何かしらのレスポンスが返ってきた場合に行われる処理になります。

    自分も素人なので正しい解説になっているかわかりませんがこんなところじゃないでしょうか。

    キャンセル

  • 2016/09/21 13:54 編集

    requestはあくまでもリクエストです。リクエストが完了しているだけで通信は完了していません。②はリクエスト直後に実行されます。一方、requestの括弧の中は、通信が完了した時に実行されます。
    ゆえに request → 外側のprint → 内側のprint の順で実行されます。

    非同期処理とかクロージャ(Closure)の勉強をして下さい。

    p.s.
    被ってすみませんw

    キャンセル

  • 2016/09/21 16:25

    お二方ともありがとうございます。
    Alamofireが非同期通信を行うものだとは存じませんでした。
    おかげさまでスッキリしました!

    キャンセル

+1

また、投稿内容から少しずれるかもしれませんが、 
Alamofire内においても値(10)のみ取得したいです。 

Optional型の勉強をして下さい。
[Swift] Optional 型についてのまとめ Ver2
どこよりも分かりやすいSwiftの"?"と"!"

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/21 13:35

    とても分かりやすかったです!ありがとうございます。
    " ! " を末尾につければいいんですね。
    Optional型の理解が浅いためにデバッグでよく躓いていたため、とてもありがたい記事でした。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る