用API响应Swift填充表

Wes*_*Cho 4 json uitableview ios swift alamofire

我试图将搜索结果显示在tableView上。我相信我已经正确解析了JSON,唯一的问题是结果不会显示在tableView上。

这是代码:

var searchText : String! {
        didSet {
            getSearchResults(searchText)
        }
    }

    var itemsArray = [[String:AnyObject]]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.tableView.reloadData()

    }

    // MARK: - Get data

    func getSearchResults(text: String) {

        if let excapedText = text.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {

            Alamofire.request(.GET, "https://api.duckduckgo.com/?q=\(excapedText)&format=json")
                .responseJSON { response in
                    guard response.result.error == nil else {

                        // got an error in getting the data, need to handle it
                        print("error \(response.result.error!)")
                        return

                    }

                    let items = JSON(response.result.value!)

                    if let relatedTopics = items["RelatedTopics"].arrayObject {

                        self.itemsArray = relatedTopics as! [[String:AnyObject]]
                    }

                    if self.itemsArray.count > 0 {

                        self.tableView.reloadData()
                    }

            }

        }
    }


    // MARK: - Table view data source

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

        return 1
    }

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

        return 6 // itemsArray.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("SearchResultCell", forIndexPath: indexPath) as! SearchResultCell

        if itemsArray.count > 0 {

            var dict = itemsArray[indexPath.row]
            cell.resultLabel?.text = dict["Text"] as? String

        } else {

            print("Results not loaded yet")

        }

        return cell
    }
Run Code Online (Sandbox Code Playgroud)

如果我有一个静态的API请求,我认为这段代码会起作用,因为我可以获取viewDidLoad并避免很多.isEmpty检查。

当我运行程序时,我得到6 Results not loaded yet(来自printin cellForRowAtIndexPath)。

当完成处理程序被调用时response in,它下降到self.items.count > 3(通过)然后命中self.tableView.reloadData(),它什么也没做(我在上面设置了一个断点来检查)。

我的代码有什么问题?

编辑

 if self.itemsArray.count > 0 {

                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            self.tableView.reloadData()

                        })
                    }
Run Code Online (Sandbox Code Playgroud)

尝试了这个,但是tableView仍然没有重新加载,即使在调用alamofire处理程序之前重新加载了6次...

这是一件奇怪的事情,很明显在hander被调用之前,我itemsArray.count将为0,所以这就是我得到的原因Results not loaded yet。我弄清楚了为什么重复六遍。我将其设置为numberOfRowsInSection...所以@Rob,我无法检查,dict["Text"]或者cell.resultLabel?.text因为它们从未被调用。不过,“文本”是正确的,这是指向JSON的链接:http : //api.duckduckgo.com/? q= DuckDuckGo& format=json& pretty=1

在此处输入图片说明

另外,我确实将标签链接到自定义单元格类 SearchResultCell

在此处输入图片说明 在此处输入图片说明

最后,我得到了可见的结果。

在此处输入图片说明

Rob*_*Rob 6

两个问题。

  1. 一个问题是prepareForSegue

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let searchResultTVC = SearchResultsTVC()
        searchResultTVC.searchText = searchField.text
    }
    
    Run Code Online (Sandbox Code Playgroud)

    那不是使用已经实例化的“目标”视图控制器,而是创建第二个SearchResultsTVC,设置第二个,searchText然后使其超出范围并被释放,从而丢失搜索文本。

    相反,您想要:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let searchResultTVC = segue.destination as? SearchResultsTVC {
            searchResultTVC.searchText = searchField.text
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您不应该依赖didSet目标视图控制器来触发搜索,因为该属性是在实例化表视图之前由源视图控制器设置的。在加载视图(viewDidLoad)之前,您不希望启动搜索。

    我会建议更换didSet逻辑,只是执行搜索viewDidLoad的那个SearchResultsTVC

我的原始答案如下,讨论原始问题中提供的代码。

-

我使用了最初在问题中提供的代码,并且工作正常。我个人可能会进一步简化它:

  • 消除中的硬编码“ 6” numberOfRowsInSection,因为这将在控制台中给您带来误报错误;

  • 转义的百分比不太正确(某些字符将滑过,未转义);与其专注于自己的正确方法,不如让Alamofire使用parameters

  • 我个人会消除SwiftyJSON,因为它不提供任何价值... Alamofire已经为我们完成了JSON解析。

无论如何,我的简化格式如下:

class ViewController: UITableViewController {

    var searchText : String!

    override func viewDidLoad() {
        super.viewDidLoad()

        getSearchResults("DuckDuckGo")
    }

    var itemsArray: [[String:AnyObject]]?

    func getSearchResults(text: String) {
        let parameters = ["q": text, "format" : "json"]
        Alamofire.request("https://api.duckduckgo.com/", parameters: parameters)
            .responseJSON { response in
                guard response.result.error == nil else {
                    print("error \(response.result.error!)")
                    return
                }

                self.itemsArray = response.result.value?["RelatedTopics"] as? [[String:AnyObject]]
                self.tableView.reloadData()
        }
    }

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return itemsArray?.count ?? 0
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SearchResultCell", for: indexPath) as! SearchResultCell

        let dict = itemsArray?[indexPath.row]
        cell.resultLabel?.text = dict?["Text"] as? String

        return cell
    }

}
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到以下信息:

在此处输入图片说明

问题必须放在其他地方。也许在情节提要中。也许是在searchText您未与我们共享的更新代码中(这会通过触发查询didSet)。很难说。但这在您提供的代码片段中似乎不是问题。

但是,在进行调试时,请确保不要在第一次调用表视图委托方法时和第二次调用时(由responseJSON块触发)合并它们。通过消除中的硬编码“ 6” numberOfRowsInSection,可以减少一些误报。