我试图让搜索结果显示在 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
此外,我确实将标签链接到自定义单元格类 SearchResultCell
最后,我得到了可见的结果。
最佳答案
两个问题。
一个问题是
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 } }
您不应依赖目标 View Controller 中的
didSet
来触发搜索,因为该属性甚至在 TableView 实例化之前就已由源 View Controller 设置。在 View 加载 (viewDidLoad
) 之前,您不想启动搜索。我建议替换
didSet
逻辑,并只在SearchResultsTVC
的viewDidLoad
中执行搜索。
我的原始答案,讨论原始问题中提供的代码如下。
--
我使用了问题中最初提供的代码,并且运行良好。就个人而言,我可能会进一步简化它:
消除
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
}
}
当我这样做时,我得到了以下信息:
问题必须在别处解决。也许它在 Storyboard中。可能是在更新 searchText
的代码中您没有与我们共享(这会通过 didSet
触发查询)。这很难说。但这在您提供的代码片段中似乎不是问题。
但是在进行调试时,请确保不要将第一次调用 TableView 委托(delegate)方法和第二次调用它们混为一谈,因为它们是由 responseJSON
block 触发的。通过消除 numberOfRowsInSection
中的硬编码“6”,这将减少一些误报。
关于ios - 使用 API 响应 Swift 填充表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33684574/