2016-06-22 3 views
1

私は、Webサービスによって提供される項目のリストを記入したいtableViewを持っています。このサービスは、ステータス(成功または失敗)および表示(文字列の配列)を持つJSONオブジェクトを返します。 viewDidLoadでNSURLSessionタスクからインスタンス変数に値を取得するにはどうすればよいですか?

IメソッドはJSONオブジェクトを受信し、辞書にそれを置く

func getShowsFromService() { 
    // Send user data to server side 
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php") 

    // Create session instance 
    let session = NSURLSession.sharedSession() 

    var json:NSDictionary = [:] 

    // Create the task 
    let task = session.dataTaskWithURL(myURL!) { //.dataTaskWithRequest(request) { 
     (data, response, error) in 

     guard let data = data else { 
      print("Error: \(error!.code)") 
      print("\(error!.localizedDescription)") 
      return 
     } 

     do { 
      json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary 
     } catch { 
      print (error) 
     } 

     let sts = json["status"] as! NSString 
     print("\(sts)") 
    } 

    // Resume the task so it starts 
    task.resume() 

    let shows = json["shows"] as! NSArray 
    for show in shows { 
     let thisshow = show as! String 
     showsArray.append(thisshow) 
    } 

    // Here I get "fatal error: unexpectedly found nil while unwrapping an Optional value" 

} 

)カスタムメソッドgetShowsFromService(呼び出します。次に、その辞書を使ってjson ['shows']を呼び出し、showsArrayというインスタンス変数に格納したい番組の配列を取得します。考え方は、データを書き込むために、tableView(cellForRowAtIndexPath)でshowsArrayを使用することです。

問題は、辞書を変数に入れることができないことです。私がタスクの中でそれをしようとすると、私はself.showsArrayを呼び出す必要があると言うエラーを受け取り、もしそうした場合、データは配列の中に入りません。私が仕事の外でそれをするなら、私はunwrapに無限の値を強制しようとしているので、私はエラーを出します。

タスク内で作成されたディクショナリをshowsArray varに出力するにはどうすればよいですか?

答えて

0

dataTaskWithURLメソッドは非同期呼び出しを行います。したがって、task.resume()を実行すると直ちに次の行にジャンプし、json ["shows"]はこの時点で辞書が空のためnilを返します。

このロジックをクラスのどこかの補完ハンドラに移動することをお勧めします。線に沿って何か:

func getShowsFromService() { 
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php") 
    let session = NSURLSession.sharedSession() 
    let task = session.dataTaskWithURL(myURL!, completionHandler: handleResult) 
    task.resume() 
} 

//-handle your result 
func handleResult(data: NSData?, response: NSURLResponse?, error: NSError?) { 
    guard let data = data else { 
     print("Error: \(error!.code)") 
     print("\(error!.localizedDescription)") 
     return 
    } 

    do { 
     if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary { 
      if let shows = json["shows"] as! NSArray { 
       //- this is still in a separate thread 
       //- lets go back to the main thread! 
       dispatch_async(dispatch_get_main_queue(), { 
        //- this happens in the main thread 
        for show in shows { 
         showsArray.append(show as! String) 
        } 
        //- When we've got our data ready, reload the table 
        self.MyTableView.reloadData() 
        self.refreshControl?.endRefreshing() 
       }); 
      } 
     } 
    } catch { 
     print (error) 
    } 
} 

上記のスニペットは(私は運動場の気圧へのアクセス権を持っていけない)のガイドとして役立つはずです。

次の点に注意してください: をできるだけ早くタスクが完了すると(非同期 - >別のスレッドは)それがエラーをチェックし、ない場合は、それが自分のタスクを実行するために、ディスパッチャを使用する新しい機能handleResultを呼び出しますメインスレッド私はshowsArraysがクラスプロパティであると仮定しています。

私はこのことができます願ってい

EDIT:

はできるだけ早くあなたのデータをフェッチすると、あなたが(上記の更新されたコード)テーブルをリロードする必要があります。リフレッシュコントロールを使用することができます(クラスプロパティとして宣言します)。

var refreshControl: UIRefreshControl! 

、あなたのデータを取得し終えたとき、あなたはリフレッシュすることができます:

self.MyTableView.reloadData() 
self.refreshControl?.endRefreshing() 

これは、行やセクションを移入するためにあなたのデリゲートメソッドを呼び出します。

+0

ヘルプDanielに感謝します。私はコードを使用してみましたが、json = let NSJSONSerialization.JSONObjectWithData(データ、オプション:NSJSONReadingOptions())を試してみましょう。 NSDictionary {私はエラーが発生します(条件付きバインディングの初期化子にはNSDictionaryではなくOptional型が必要です)。 – cesarcarlos

+0

私は実際にその部分を修正して、そのデータをshowsArrayクラスのプロパティに取得することができました。問題は今、cellForRowAtIndexPathがこの配列からデータをロードしていないことです。アレイが構築されるまでに、cellForRowAtIndexPathが既に呼び出されている可能性がありますか? – cesarcarlos

+0

あなたは大歓迎です!はい。データが取得されたときにリロードテーブルメソッドを呼び出すと、更新された内容がすぐに表示されるようにすることができます。私は答えを更新する –

関連する問題