我发现我的 code 有一个小问题。我遇到的问题是我的限制调用工作正常,但是如果您运行它并多次切换显示的金额选项,则会出现索引超出范围错误。
似乎只有当您快速运行它或不更改搜索时才会发生这种情况。我花了 4 个小时在这上面,感觉我没有看到一些真正简单的东西!谢谢!
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath)
let searchResult = searchResultsController.searchResults[indexPath.row]
cell.textLabel?.text = searchResult.title
cell.detailTextLabel?.text = searchResult.creator
return cell
}
//MARK: Actions
@IBAction func filterButtonPressed(_ sender: UIBarButtonItem) {
if limitSearchButton.title == "show 10" {
limit.limit = "10"
limitSearchButton.title = "show 5"
print("limit is \(String(describing: limit.limit))")
searchBarSearchButtonClicked(searchBar)
tableView.reloadData()
} else if limitSearchButton.title == "show 5"{
limit.limit = "5"
limitSearchButton.title = "show 10"
print("limit is \(String(describing: limit.limit))")
searchBarSearchButtonClicked(searchBar)
tableView.reloadData()
}
}
@IBAction func segmentedControlChanged(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
searchBarSearchButtonClicked(searchBar)
self.tableView.reloadData()
}else if sender.selectedSegmentIndex == 1 {
searchBarSearchButtonClicked(searchBar)
self.tableView.reloadData()
}else {
searchBarSearchButtonClicked(searchBar)
self.tableView.reloadData()
}
}
}
extension SearchResultsTableViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let searchTerm = searchBar.text else { return }
switch segmentedControl.selectedSegmentIndex {
case 0:
resultType = .software
case 1:
resultType = .musicTrack
case 2:
resultType = .movie
default:
break
}
searchResultsController.performSearch(searchTerm: searchTerm, resultType: resultType, limit: limit) {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
我希望通过我的打印语句和过滤功能,获得限制金额并将其与更新我的按钮一起返回。但在使用了几次 UIBarButton 函数后我什么也没得到。
最佳答案
为什么崩溃?
这是线程之间的竞争条件(当您异步获取新结果时)。
有时您尝试显示 4 个元素,但您的数据源刚刚更新,现在有 3 个元素。您在模型更改方面缺乏同步。
通过对 reloadData 的所有调用,很有可能与网络请求返回的时间相同,我怀疑这会导致崩溃。
API 修复
强制并发的一种方法是将所有并发同步工作移至 API,这样 API 的使用者就不必考虑它是如何工作的。 (不再有客户端调度异步调用)
在 API 逻辑中,使用 DispatchQueue.main.async { }
block 包装每个 completion()
处理程序调用,以及对 ViewController 中访问的公共(public)属性的更改。该调度队列将强制确保不同线程上不会发生 UI 更新。
您在 ViewController 中调用的任何 API 都将位于同一主线程上,因此只要将这些 block 放在每个适当的位置,您就可以获得线程安全。
由于您没有提供该代码,我将提供另一个 iOS 项目的代码示例,地址为 Lambda School .
您的 URLSession/网络代码中的逻辑将如下所示:
URLSession.shared.dataTask(with: url) { (data, _, error) in
if let error = error {
print("Error fetching quakes: \(error)")
DispatchQueue.main.async { // Wrap every call to completion()
completion(nil, error)
}
return
}
guard let data = data else {
DispatchQueue.main.async {
completion(nil, QuakeError.noDataReturned)
}
return
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let quakeResults = try decoder.decode(QuakeResults.self, from: data)
DispatchQueue.main.async {
// Setting a public property needs to be also protected
// inside your main.async blocks, in addition to your
// completion() handler calls
self.quakes = quakeResults.features // protect public properties
completion(quakes, nil)
}
} catch {
DispatchQueue.main.async {
completion(nil, error)
}
}
}.resume()
关于arrays - 如何修复 JSON 解析应用程序中的 'Index Out Of Range' 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58679040/