お世話になります。長文になりますがお許しください。
###前提・実現したいこと
Swiftで栄養管理アプリを作っています。
大まかな機能としては、バーコードでスキャンした製品の栄養バランスをグラフ化するというものです。
FatSecretという全世界の製品を網羅する栄養データベースにアクセスし、そのデータをグラフに反映させようとしています。
###実現したい動作フロー
下記フローの中で4の箇所を実現するために、まずはサンプルデータで上手くいくかどうかを試しています。
0. scanViewControllerクラスのfoundCodeメソッドでバーコード番号読み取り
0. nutritionDisplayViewControllerクラスのfoodFindIdForBarcodeメソッドへ1を渡し、製品IDを取得
0. nutritionDisplayViewControllerクラスのfoodGetメソッドへ2を渡し、栄養パラメータを取得
0. BarChartViewクラスに3を投げてグラフを作成
0. scanViewControllerクラスに戻り、transitionメソッドでnutritionDisplayViewControllerクラスへ画面遷移
###発生している問題・エラーメッセージ
FatSecretのデータベースへアクセス中にView(barChartView)へグラフを書き込もうとすると下記エラーが発生してしまいます。
fatal error: unexpectedly found nil while unwrapping an Optional value
エラーが発生している箇所は特定できているのですが、原因がわからず困っております。何卒よろしくお願いします。
またUI上では、スキャン後に画面遷移する仕様で画面遷移はするのですが、下記のメッセージが表示されてしまいます。(投稿者自身が、データがないときにこのメッセージを表示するようにしています)
"You need to provide data for the chart"
###該当のソースコード
swift
1// scanViewController.swift 2 3// バーコード番号を読み取る関数 4public func foundCode(scannedBarcode: String) { 5 nutritionDisplayViewController().foodFindIdForBarcode(scannedBarcode) 6 //省略 7 transition() 8} 9 10func transition() { 11 let next = self.storyboard?.instantiateViewControllerWithIdentifier("modal") as! nutritionDisplayViewController 12 self.navigationController?.pushViewController(next, animated: true) 13 //print(test) 14}
swift
1// nutritionDisplayViewController.swift 2 3public class nutritionDisplayViewController: UIViewController, ChartViewDelegate { 4 5 @IBOutlet weak var barChartView: BarChartView! 6 7 var months: [String]! //サンプルデータ 8 var nutritions: [[String: String?]] = [] //FatSecretからとってくる栄養パラメータ 9 10 override public func viewDidLoad() { 11 super.viewDidLoad() 12 // Do any additional setup after loading the view, typically from a nib. 13 } 14 15 // 製品のバーコードに紐づけられた独自のIDを取得 16 public func foodFindIdForBarcode(scannedBarcode:String) { 17 18 let URL = "http://platform.fatsecret.com/rest/server.api" 19 var parameters = [String: String]() 20 21 parameters["format"] = "json" 22 parameters["method"] = "food.find_id_for_barcode" 23 parameters["barcode"] = scannedBarcode 24 25 parameters["oauth_version"] = "1.0" 26 //省略 27 parameters["oauth_signature"] = oauthSignatureForMethod("GET", url: NSURL(string: URL)!, parameters: parameters) 28 29 // FatSecretにリクエスト 30 Alamofire.request(.GET, URL, parameters: parameters) 31 .responseJSON { response in 32 guard let object = response.result.value else { 33 return 34 } 35 let json = JSON(object) 36 json.forEach { (_, json) in 37 let nutrition: [String: String?] = [ 38 "barcode": json["barcode"].string 39 ] 40 self.nutritions.append(nutrition) 41 } 42 self.foodGet(json["food_id"]["value"].string!) 43 44 if let JSON = response.result.value { 45 print("JSON: \(JSON)") 46 } 47 } 48 } 49 50 // foodFindIdForBarcode()で取得したIDをもとに栄養パラメータを取得(この関数内でのネットワーク通信中にエラーが発生しています) 51 public func foodGet(fid:String) { 52 53 //省略(foodFindIdForBarcodeと同様) 54 55 Alamofire.request(.GET, URL, parameters: parameters) 56 .responseJSON { response in 57 guard let object = response.result.value else { 58 return 59 } 60 let json = JSON(object) 61 json.forEach { (_, json) in 62 let nutrition: [String: String?] = 63 ["food_id": json["food_id"]["value"].string, 64 "brand_name": json["food"]["brand_name"].string, 65 "vitamin_c": json["food"]["servings"]["serving"]["vitamin_c"].string 66 ] 67 self.nutritions.append(nutrition) 68 } 69 70 if let JSON = response.result.value { 71 print("JSON: \(JSON)") 72 } 73 74 /*********************/ 75 self.barChartView.delegate = self //ここで "fatal error: unexpectedly found nil while unwrapping an Optional value" 76 /*********************/ 77 78 self.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 79 let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0, 4.0, 18.0, 2.0, 4.0, 5.0, 4.0] 80 81 self.setChart(self.months, values: unitsSold) 82 self.barChartView.descriptionText = "" 83 self.barChartView.xAxis.labelPosition = .Bottom 84 self.barChartView.backgroundColor = UIColor(red: 189/255, green: 195/255, blue: 199/255, alpha: 1) 85 86 self.barChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .EaseInBounce) 87 88 let ll = ChartLimitLine(limit: 10.0, label: "Target") 89 } 90 viewDidAppear(true) 91 } 92 93 override public func viewDidAppear(animated: Bool) { 94 } 95 96 /*----グラフ作成(ios-charts参考)----*/ 97 public func setChart(dataPoints: [String], values: [Double]) { 98 barChartView.noDataText = "You need to provide data for the chart" 99 100 var dataEntries: [BarChartDataEntry] = [] 101 102 for i in 0..<dataPoints.count { 103 let dataEntry = BarChartDataEntry(value: values[i], xIndex: i) 104 dataEntries.append(dataEntry) 105 } 106 107 let chartDataSet = BarChartDataSet(yVals: dataEntries, label: "Units Sold") 108 let chartData = BarChartData(xVals: months, dataSet: chartDataSet) 109 110 chartDataSet.colors = ChartColorTemplates.colorful() 111 112 barChartView.data = chartData 113 } 114 115 public func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, datdex: Int, highlight: ChartHighlight) { 116 print("\(entry.value) in \(months[entry.xIndex])") 117 } 118 119 /*---- OAuth関連 ----*/ 120 //省略 121
###Storyboard
Storyboard全体のイメージです。nutritionDisplayViewControllerを選択しています。
nutritionDisplayViewController内のBarChartViewを選択しています。
###試したこと
1.nilとなっている箇所の特定
エラー箇所特定のため、print("(1)")とprint("(2)")を書いてみたところ、(1)のみ表示されるため、self.barChartView.delegate = selfが上手くいっていないと思います。
nilが返されていると思われるself.barChartView.delegateの情報を見ようと、print(self.barChartView.delegate)で出力してみましたが、何も出力されません。
2.viewDidLoad内への移動
下記の部分をviewDidLoad内に書いてみました。動作するものの、これではネットワーク通信で取得したデータを反映させようがないのでダメですね。
swift
1self.barChartView.delegate = self 2self.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 3 let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0, 4.0, 18.0, 2.0, 4.0, 5.0, 4.0] 4 5self.setChart(self.months, values: unitsSold) 6self.barChartView.descriptionText = "" 7self.barChartView.xAxis.labelPosition = .Bottom 8self.barChartView.backgroundColor = UIColor(red: 189/255, green: 195/255, blue: 199/255, alpha: 1) 9 10self.barChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .EaseInBounce) 11 12let ll = ChartLimitLine(limit: 10.0, label: "Target")
3.response.dataの確認
2016-09-20 12:46:13.107 FoodAPISample[2316:1015696] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x144d93660 V:|-(20)-[UIInputSetContainerView:0x144d91820] (Names: '|':UITextEffectsWindow:0x144d8eab0 )>", "<NSLayoutConstraint:0x144d7fc70 'UIInputWindowController-top' V:|-(0)-[UIInputSetContainerView:0x144d91820] (Names: '|':UITextEffectsWindow:0x144d8eab0 )>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x144d93660 V:|-(20)-[UIInputSetContainerView:0x144d91820] (Names: '|':UITextEffectsWindow:0x144d8eab0 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
###補足情報(言語/FW/ツール等のバージョンなど)
#####バージョン情報
Alamofire 3.4
Charts 2.2.5
XCode 7
iOS 9.3.5
#####利用しているライブラリ
ios-charts
Alamofire
SwiftyJSON
#####利用しているAPI
FatSecret Platform REST API

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/20 10:05
2016/09/20 10:37
2016/09/20 13:30
2016/09/21 02:15
2016/09/21 02:38
2016/09/21 03:30