2017-08-26 11 views
0

私は迅速なプログラミングで非常に新しいです。私はWebサービスに精通していません。私は詩のためのiOSモバイルアプリケーションを作りたいと思っています。Swift 3 Xcode 8で非同期タスクを最初に完了する方法はありますか?

jsonでエンコードされたデータを取得できましたが、私の問題はここで私のテーブルビューに転送できません。私がそれを実行したとき、問題は非同期タスクのためだと思う。それは非同期タスクであるため、委任されたfuncが実行された後にタスクが実行されるだけであるため、name.countが0のときにtableview(numberOfRows)の委任関数が実行されます。だから私のTableViewで私のデータを見ることができないのです...私は誰かがここで私を助けることを願っています。私はグーグルで、Completion Handlersを試してみました(これは何のために使われているのか分かりません)。そして、私はそれを同期に変えてみました。あなたの完了ブロックで

import UIKit 
import Foundation 

class TimelineViewController: UIViewController { 
    @IBOutlet weak var contentTableView: UITableView! 
    var name = [String]() 
    var bio = [String]() 

    @IBOutlet weak var oPostBtn: UIButton! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     getPoems() 
    } 

    func getPoems() 
    { 
     let url:NSURL = NSURL(string: "http://192.168.1.6/Test/feed1.php")! 
     let request:NSMutableURLRequest = NSMutableURLRequest(url:url as URL) 

     request.httpMethod = "GET" 

     NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main){(response, data, error) in } 

     let task = URLSession.shared.dataTask(with: request as URLRequest) { 
       data, response, error in 

       if error != nil { 
        print("Error = \(error)") 
        return 
       } 
       do { 
        print("Response=\(response)") 

        let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) 
        print("Response data = \(responseString)") 

        //Converting response to NSDictionary 
        var json: NSDictionary! 
        json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary 

        //getting the JSONArray poems from the response 
        let returnPoems: NSArray = json["returnPoems"] as! NSArray 

        print(returnPoems); 


        //looping through all the json objects in the array teams 
        for i in 0 ..< returnPoems.count{ 


         let aObject = returnPoems[i] as! [String : AnyObject] 


         self.name.append(aObject["fullName"] as! String) 
         self.bio.append(aObject["Bio"] as! String) 
         //displaying the data 

         print("Fullname -> ", self.name) 
         print("Bio ->", self.bio) 

         print("===================") 
         print("") 

        } 


       } 
       catch { 
        print("ERROR: \(error)") 
       } 

     } 
     task.resume() 

    } 

} 

extension TimelineViewController: UITableViewDelegate, UITableViewDataSource { 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 


     let cell = contentTableView.dequeueReusableCell(withIdentifier: "PoemCell") 


     cell?.textLabel?.text = name[indexPath.row] 
     cell?.detailTextLabel?.text = bio[indexPath.row] 

     return cell! 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

     return name.count 
    } 
    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     print("You selected cell #\(indexPath.row)!") 

     let indexPath = tableView.indexPathForSelectedRow! 
     let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell 

    } 
} 
+0

、あなたが 'NAME'と' bio'アレイを構築完了したら、 'DispatchQueue.main.async {self.tableView.reloadData(呼び出し)} 'を実行してテーブルをリフレッシュします。 – Rob

+0

@RobありがとうRob!私はこれに時間を費やしてきたとは信じられない..また、あなたが言ったことをした、あなたは正しい!正常に動作します。ありがとうございました! – Nadz

答えて

1

、あなたがnamebioのアレイを構築完了したら、メインキューからreloadDataを呼び出すことによって、テーブルを更新:

DispatchQueue.main.async { 
    self.tableView.reloadData() 
} 

いくつかの他にはありました私が提案するもの:

  • これを削除する必要があります。NSURLConnectionコード。それは冗長な要求を実行しており、応答では何もしていません。それにもかかわらず、廃止予定のAPIであり、削除する必要があります。

  • NSURLの代わりにURLを使用する必要があります。

  • NSMutableURLRequestの代わりにURLRequestを使用してください。

  • NSStringではなくStringを使用してください。

  • あなたはNSArrayNSDictionaryのではなく、スウィフトArrayDictionaryを使用する必要があります。

  • didSelectRowAtの署名が間違っています。 IndexPathではなく、NSIndexPathを使用してください。

  • URLSessionバックグラウンドキューからnameおよびbioアレイを更新しています。これはスレッドセーフではありません。これを解決するには、これらをメインキューから更新して、追加の同期を行う必要がないようにします。

  • 私はこれらの2つの異なる配列を取り除き、カスタムオブジェクトの単一の配列Poemを持っていることをお勧めします。これにより、コードがはるかに簡単になります。たとえば、name配列を並べ替える場合は、個別のbio配列を更新するにはどうすればよいのですか?単一のカスタムオブジェクトを使用するとこの問題は解消されます)。

    このよう

:あなたの完了ブロックで

struct Poem { 
    let name: String 
    let bio: String 

    init?(dictionary: [String: Any]) { 
     guard let name = dictionary["fullName"] as? String, 
      let bio = dictionary["Bio"] as? String else { 
       print("Did not find fullName/Bio") 
       return nil 
     } 

     self.name = name 
     self.bio = bio 
    } 
} 

class TimelineViewController: UIViewController { 

    @IBOutlet weak var contentTableView: UITableView! 

    var poems = [Poem]() 

    @IBOutlet weak var oPostBtn: UIButton! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     getPoems() 
    } 

    func getPoems() { 
     let url = URL(string: "http://192.168.1.6/Test/feed1.php")! 
     var request = URLRequest(url: url) 

     request.httpMethod = "GET" 

     let task = URLSession.shared.dataTask(with: request) { data, response, error in 
      guard let data = data, error == nil else { 
       print("Error = \(error?.localizedDescription ?? "Unknown error")") 
       return 
      } 

      if let response = response { 
       print("Response=\(response)") 
      } 

      if let responseString = String(data: data, encoding: .utf8) { 
       print("Response data = \(responseString)") 
      } 

      // Converting response to Dictionary 

      guard let json = try? JSONSerialization.jsonObject(with: data), 
       let responseObject = json as? [String: Any], 
       let returnPoems = responseObject["returnPoems"] as? [[String: Any]] else { 
        print("did not find returnPoems") 
        return 
      } 

      print(returnPoems) 

      // dispatch the update of model and UI to the main queue 

      DispatchQueue.main.async { 
       self.poems = returnPoems.flatMap { Poem(dictionary: $0) } 
       self.contentTableView.reloadData() 
      } 
     } 

     task.resume() 
    } 

} 

extension TimelineViewController: UITableViewDelegate, UITableViewDataSource { 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = contentTableView.dequeueReusableCell(withIdentifier: "PoemCell", for: indexPath) 

     let poem = poems[indexPath.row] 

     cell.textLabel?.text = poem.name 
     cell.detailTextLabel?.text = poem.bio 

     return cell 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return poems.count 
    } 

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
     print("You selected cell #\(indexPath.row)!") 

     // let indexPath = tableView.indexPathForSelectedRow!       // why do this? ... the indexPath was passed to this function 
     // let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell // why do this? ... you don't care about the cell ... go back to you model 

     let poem = poems[indexPath.row] 

     // do something with poem, e.g. 

     print(poem) 
    } 
} 
関連する問題