Отображение данных JSON в TableView с использованием SwiftyJSON и Alamofire

Я хочу показать данные JSON, полученные с сервера, в табличном представлении. Проблема в том, что я не могу заставить его отображаться на нем. Я пробовал несколько разных методов и много искал, чтобы найти решение, но не могу.

Мой код (весь) показан ниже, и я надеюсь, что кто-нибудь сможет мне помочь. Заранее спасибо.

import UIKit
import Alamofire
import SwiftyJSON

class MasterViewController: UITableViewController {

var tableTitle = [String]()
var tableBody = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    getJSON()

}

func getJSON(){

    Alamofire.request(.GET, "http://announcement.vassy.net/api/AnnouncementAPI/Get/").responseJSON { (Response) -> Void in

        // checking if result has value
        if let value = Response.result.value {

            let json = JSON(value)

            for anItem in json.array! {

                let title: String? = anItem["Title"].stringValue
                let body: String? = anItem["Body"].stringValue
                self.tableTitle.append(title!)
                self.tableBody.append(body!)

            }

        }

    }

    self.tableView.reloadData()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// Table View Stuff

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.tableTitle.count
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell

    // cell config
    cell.title!.text = tableTitle[indexPath.row]
    cell.body!.text = tableBody[indexPath.row]
    return cell

}

}

person omar    schedule 15.03.2016    source источник


Ответы (2)


Сетевой запрос Alamofire является асинхронным, то есть вы не можете знать, когда будет возвращен результат.

Проблема здесь в том, что вы перезагружаете tableView вне области действия запроса Alamofire, поэтому он выполняется до того, как данные вернутся.

Перезагрузка должна происходить в той же области видимости и в основном потоке, например:

func getJSON(){

    Alamofire.request(.GET, "http://announcement.vassy.net/api/AnnouncementAPI/Get/").responseJSON { (Response) -> Void in

        // checking if result has value
        if let value = Response.result.value {

            let json = JSON(value)

            for anItem in json.array! {

                let title: String? = anItem["Title"].stringValue
                let body: String? = anItem["Body"].stringValue
                self.tableTitle.append(title!)
                self.tableBody.append(body!)

            }

            dispatch_async(dispatch_get_main_queue()) {
                self.tableView.reloadData()             
            }

        }

    }

}
person Eric Aya    schedule 15.03.2016

Я думаю, что @Eric сказал почти все в своем ответе, тем не менее, это не очень хорошее решение в дизайне: сохранить код для выполнения сетевого запроса в одном и том же UITableViewController, это сохранить пару между двумя вещами, которые являются независимыми и изменяются по разным причинам.

Мой совет состоит в том, чтобы разделить две части кода, разделив зависимость между двумя слоями. Таким образом, когда вам нужно изменить что-либо, связанное с вашим обработчиком сетевых запросов, вам не нужно менять его в любом месте, где вы делаете тот же запрос, это совет !!!.

Если вы хотите это сделать, вы можете использовать замыкания для обработки асинхронного поведения Alamofire, пропустив completionHandlerвнутри оболочки, которую вы создаете для обработки сетевых запросов, например, давайте определим простую оболочку, используя шаблон singleton (это просто для цели объяснения образца, вы можете обращаться с ним, как хотите).

import AlamofireImage
import SwiftyJSON

class NetworkHandler { 

   /// The shared instance to define the singleton.
  static let sharedInstance = RequestManager()


  /**
  Private initializer to create the singleton instance.
  */
  private init() { }

  func getJSON(completionHandler: (json: JSON?, error: NSError?) -> Void) {

      Alamofire.request(.GET, http://announcement.vassy.net/api/AnnouncementAPI/Get/).responseJSON { response in

        switch(response.result) {
        case .Success(let value):

            let json = JSON(value)
            completionHandler(json: json, error: nil)

        case .Failure(let error):
            completionHandler(json: nil, error: error)
        }
    }
  }
}

Затем в вашем UITableViewController вы можете вызвать новую оболочку для Alamofire следующим образом:

class MasterViewController: UITableViewController {

   var tableTitle = [String]()
   var tableBody = [String]()

   override func viewDidLoad() {
       super.viewDidLoad()
       // Do any additional setup after loading the view, typically from a nib.

       NetworkHandler.sharedInstance.getJSON { [weak self] (json, error) -> Void in

         // request was made successful
         if error == nil {
            for anItem in json.array! {
               let title: String? = anItem["Title"].stringValue
               let body: String? = anItem["Body"].stringValue
               self.tableTitle.append(title!)
               self.tableBody.append(body!)
            }

            dispatch_async(dispatch_get_main_queue()) {
                self.tableView.reloadData()             
            }
         }
       }
    }

    // rest of your code
 }

Приведенным выше способом вы сохраняете код развязанным, это хороший дизайн.

Я надеюсь, что это поможет вам

person Victor Sigler    schedule 15.03.2016