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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

2回答

1863閲覧

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

takhub

総合スコア28

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2016/09/21 03:28

編集2016/09/21 03:32

###前提・実現したいこと
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("")の部分を削除するようにします。

###該当のソースコード

swift

1public class nutritionDisplayViewController: UIViewController, ChartViewDelegate { 2 3 @IBOutlet weak var barChartView: BarChartView! 4 5 var nutritions: [[String: String?]] = [] //APIとの通信に用いるパラメータ 6 7 //@IBOutlet weak var idLabel: UILabel! 8 override public func viewDidLoad() { 9 super.viewDidLoad() 10 // Do any additional setup after loading the view, typically from a nib. 11 12 //グラフ作成ライブラリChartsを用いたグラフ作成処理 13 setChart(parameter, values: unitsSold) 14 //省略 15 } 16 17 //カメラで読み取ったバーコード番号を投げて製品特有のAPI独自ID(food_id)を取得する関数 18 public func foodFindIdForBarcode(scannedBarcode:String) { 19 20 //省略 21 foodGet(food_id) 22 } 23 24 // 製品特有のAPI独自IDを投げて栄養パラメータを取得する関数 25 public func foodGet(fid:String) { 26 27 let URL = "http://platform.fatsecret.com/rest/server.api" 28 var parameters = [String: String]() 29 30 parameters["format"] = "json" 31 parameters["food_id"] = fid //製品特有のAPI独自ID 32 33 parameters["method"] = "food.get" 34 35 //OAuth関連のパラメータ設定 36 //省略 37 38 var vitamin_c: String? 39 40 Alamofire.request(.GET, URL, parameters: parameters) 41 .responseJSON { response in 42 guard let object = response.result.value else { 43 return 44 } 45 let json = JSON(object) 46 json.forEach { (_, json) in 47 let nutrition: [String: String?] = 48 ["food_id": json["food_id"]["value"].string, 49 "vitamin_c": json["food"]["servings"]["serving"]["vitamin_c"].string 50 ] 51 self.nutritions.append(nutrition) 52 } 53 54 vitamin_c = json["food"]["servings"]["serving"]["vitamin_c"].string! 55 56 print("Alamofire内でvitamin_c:\(vitamin_c)") 57 } 58 print("Alamofire外でvitamin_c:\(vitamin_c)") 59 } 60 61 override public func viewDidAppear(animated: Bool) { 62 63 } 64 65 /*------- Charts -------*/ 66 func setChart(dataPoints: [String], values: [Double]) { 67 //省略 68 } 69 70 /*------- OAuth --------*/ 71 public func oauthSignatureForMethod(method: String, url: NSURL, parameters: Dictionary<String, String>) -> String { 72 //省略 73 } 74}

###試したこと

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

###補足情報(言語/FW/ツール等のバージョンなど)
利用したライブラリとバージョン情報

Alamofire:3.4
Charts:2.2.5
SwiftyJSON


宜しくお願いします!

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Swift

1Alamofire.request(.GET, URL, parameters: parameters) 2 (※省略) 3 print("Alamofire内でvitamin_c:\(vitamin_c)") 4} 5print("Alamofire外でvitamin_c:\(vitamin_c)")

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

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

投稿2016/09/21 03:51

Y_M

総合スコア265

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takhub

2016/09/21 04:33

早速のご回答ありがとうございます! やはりその場所に記載しないといけないのですね。 そうすると別の問題が生まれてしまうのですが、知識不足で解決できず、そちらについては別途質問を投稿させていただきます。 ただ、通信完了云々というところが恥ずかしながら理解できていません。 Alamofire.request()のあとの処理であれば、すでに通信は完了していると思いますが、なぜ②の箇所では通信が完了していないのでしょうか? 逆に、素人目線ですがAlamofire.request()内だと通信中であるように思えますが、なぜprint("Alamofire内でvitamin_c:\(vitamin_c)")の場所が通信完了後となるのでしょうか?
Y_M

2016/09/21 04:52

Alamofireは非同期通信を行うためのフレームワークです。 非同期通信はご存知かもしれませんが、 「ネットワークなどでつながれているコンピュータ間で、 送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式。」 なので「Alamofire.request()」という処理を別のスレッドで処理することで、 メインスレッドでの処理を停止させずに実行できるということです。 なので今回だと「Alamofire内のprint」はその別のスレッド上で基本的に順番に。 「Alamofire外のprint」はUIなどを動かしているメインスレッドで処理するため上記のような動作になります。 また通信中という表現ですが「.responseJSON { response in」 ここ以降が通信が完了した後、 何かしらのレスポンスが返ってきた場合に行われる処理になります。 自分も素人なので正しい解説になっているかわかりませんがこんなところじゃないでしょうか。
fuzzball

2016/09/21 04:55 編集

requestはあくまでもリクエストです。リクエストが完了しているだけで通信は完了していません。②はリクエスト直後に実行されます。一方、requestの括弧の中は、通信が完了した時に実行されます。 ゆえに request → 外側のprint → 内側のprint の順で実行されます。 非同期処理とかクロージャ(Closure)の勉強をして下さい。 p.s. 被ってすみませんw
takhub

2016/09/21 07:25

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

0

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

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

投稿2016/09/21 03:48

編集2016/09/21 04:07
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takhub

2016/09/21 04:35

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問