使用API​​响应Swift填充表

时间:2015-11-13 01:37:44

标签: 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(来自print中的cellForRowAtIndexPath)。

当完成处理程序被调用response in时,它会下降到self.items.count > 3(通过),然后点击self.tableView.reloadData(),它什么都不做(我通过在它上面放置一个断点来检查)。 / p>

我的代码有什么问题?

修改

 if self.itemsArray.count > 0 {

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

                        })
                    }

试过这个但是,即使在调用alamofire hander之前重新加载了6次,tableView仍然没有重新加载...

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

enter image description here

此外,我确实将标签链接到自定义单元格类bookshelf.transaction(function (t) { return User.forge(data) // here .save(null, { transacting: t }) .then(function (user){ return Room.forge({ userId: user.id }) .save(null, { transacting: t }); }) })

enter image description here enter image description here

最后,我得到了明显的结果。

enter image description here

2 个答案:

答案 0 :(得分:4)

两个问题。

  1. 一个问题是prepareForSegue

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

    这不是使用已经实例化的“目标”视图控制器,而是创建第二个SearchResultsTVC,设置其searchText,然后让它超出范围并被取消分配,丢失搜索这个过程中的文字。

    相反,你想要:

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

    我建议更换didSet逻辑,然后在viewDidLoad的{​​{1}}中执行搜索。

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

    -

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

    • 消除了SearchResultsTVC中硬编码“6”的删除,因为这会在控制台中给出误报错误;

    • 逃脱的百分比不太正确(某些角色会滑过,未转义);而不是沉溺于自己做正确的方法,最好让Alamofire为你做这件事,使用numberOfRowsInSection;

    • 我个人消除了SwiftyJSON,因为它没有提供任何价值...... Alamofire已经为我们进行了JSON解析。

    无论如何,我的简化版本如下:

    parameters

    当我这样做时,我得到了以下内容:

    enter image description here

    问题必须在其他地方休息。也许它在故事板中。也许是在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(.GET, "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, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("SearchResultCell", forIndexPath: indexPath) as! SearchResultCell let dict = itemsArray?[indexPath.row] cell.resultLabel?.text = dict?["Text"] as? String return cell } } 更新的代码中,您没有与我们共享(通过searchText触发查询)。很难说。但它在您提供的代码段中似​​乎不是问题。

    但是在进行调试时,请确保在第一次调用表视图委托方法时以及第二次调用时不会混淆(由didSet块触发。通过消除responseJSON中的硬编码“6”,可以减少一些误报。

答案 1 :(得分:0)

我认为你应该编辑:

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 have result data -> reload , & no if no
                    if self.itemsArray.count > 0 {
                        self.tableView.reloadData()
                    }
                }else{
                    print("Results not loaded yet")
                }
        }
    }
}

并且

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

    let cell = tableView.dequeueReusableCellWithIdentifier("SearchResultCell", forIndexPath: indexPath) as! SearchResultCell
    // i 'm sure: itemsArray.count > 0 in here if in numberOfRowsInSection return itemsArray.count
    var dict = itemsArray[indexPath.row]
    cell.resultLabel?.text = dict["Text"] as? String
    return cell
}

你应该分享json结果(格式),在cellForRowAtIndexPath中打印dict,这样很容易获得帮助