首页 > 解决方案 > 如何修复 JSON 解析应用程序中的“索引超出范围”错误

问题描述

我发现我的代码有一个小问题。我遇到的问题是我的限制调用工作正常,但是如果你运行它并切换显示的数量选项几次,就会出现索引超出范围错误。

只有当你快速运行它或不改变你的搜索时,它似乎才会发生。我在这上面花了 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 函数之后,我什么也没得到。

标签: arraysswift

解决方案


为什么崩溃?

这是线程之间的竞争条件(当您异步获得新结果时)。

有时您尝试显示 4 个元素,但您的数据源刚刚更新,现在有 3 个元素。您在模型更改方面缺乏同步。

由于您对 reloadData 的所有调用,它与网络请求返回的时间相同的可能性更高,我怀疑这会导致崩溃。

API 修复

强制执行并发的一种方法是将所有并发同步工作转移到 API,因此 API 的使用者不必考虑它是如何工作的。(不再有客户端调度异步调用)

在您的 API 逻辑中,使用您的块包装每个completion()处理程序调用以及对 ViewController 中访问的公共属性的更改。DispatchQueue.main.async { }该调度队列将强制在不同的线程上不发生 UI 更新。

您在 ViewController 中调用的任何 API 都将位于同一主线程上,因此只要将这些块放在每个适当的位置,您就会获得线程安全。

由于您没有提供该代码,我将提供来自Lambda School的另一个 iOS 项目的代码示例。

你的逻辑在你的 URLSession/networking 代码中看起来像这样:

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()

推荐阅读