ios - 使用 API 响应 Swift 填充表

标签 ios json swift uitableview 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
    }

如果我有一个静态 API 请求,我认为这段代码可以工作,因为我可以在 viewDidLoad 中获取并避免大量的 .isEmpty 检查。

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

当完成处理程序调用 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()

                        })
                    }

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

奇怪的是,显然在处理程序被调用之前,我的 itemsArray.count 将为 0,所以这就是为什么我得到 Results not loaded yet 的原因。我想通了为什么它会重复 6 次;我在 numberOfRowsInSection 中设置它...所以@Rob,我无法检查 dict["Text"]cell.resultLabel?.text 因为他们永远不会被调用。 “文本”是正确的,这里是 JSON 的链接:http://api.duckduckgo.com/?q=DuckDuckGo&format=json&pretty=1

enter image description here

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

enter image description here enter image description here

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

enter image description here

最佳答案

两个问题。

  1. 一个问题是prepareForSegue:

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

    这不是使用已经实例化的“目标” View Controller ,而是创建第二个 SearchResultsTVC,设置它的 searchText 然后让它超出范围并被释放,在此过程中丢失搜索文本。

    相反,您想要:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let searchResultTVC = segue.destination as? SearchResultsTVC {
            searchResultTVC.searchText = searchField.text
        }
    }
    
  2. 您不应依赖目标 View Controller 中的 didSet 来触发搜索,因为该属性甚至在 TableView 实例化之前就已由源 View Controller 设置。在 View 加载 (viewDidLoad) 之前,您不想启动搜索。

    我建议替换 didSet 逻辑,并只在 SearchResultsTVCviewDidLoad 中执行搜索。

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

--

我使用了问题中最初提供的代码,并且运行良好。就个人而言,我可能会进一步简化它:

  • 消除 numberOfRowsInSection 中的硬编码“6”,因为这会在控制台中产生误报;

  • 转义的百分比不太正确(某些字符将滑过,未转义);与其纠结于自己做这件事的正确方法,不如让 Alamofire 使用 parameters 为你做这件事;

  • 我个人会淘汰 SwiftyJSON,因为它没有提供任何值(value)……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
    }

}

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

enter image description here

问题必须在别处解决。也许它在 Storyboard中。可能是在更新 searchText 的代码中您没有与我们共享(这会通过 didSet 触发查询)。这很难说。但这在您提供的代码片段中似乎不是问题。

但是在进行调试时,请确保不要将第一次调用 TableView 委托(delegate)方法和第二次调用它们混为一谈,因为它们是由 responseJSON block 触发的。通过消除 numberOfRowsInSection 中的硬编码“6”,这将减少一些误报。

关于ios - 使用 API 响应 Swift 填充表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33684574/

相关文章:

json - 如何使用 Swift 和 Alamofire 连接 http 服务器

ios - 每当我单击该行时,都会在 tableview 单元格中增加 clickcount 标签值

ios - 如何将主应用程序类传递给框架

ios - UINavigationBar 外观属性不适用于 iOS 8

ios - 在 YouTube 上使用 get_video 下载视频

objective-c - 触发核心位置警报

iphone - 使用 CGContext 画线

json - 错误使用未初始化的值

javascript - 使用 Angular js ng-repeat 指令过滤 json 对象

swift - 以编程方式使用 NSTextField 的 NSPopover