'Request for rect at invalid index path' 单元格点击异常

'Request for rect at invalid index path' exception on cell tap

我正在开发具有自动填充功能的搜索栏。有时在自动填充 TableView:

中点击单元格时会出现此错误

*** Assertion failure in -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UITableViewRowData.m:1849

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path ( {length = 2, path = 0 - 3})'

如果我评论这一行 searchBar.text = cell.textLabel!.text 应用程序不会崩溃。

这里是完整的函数代码:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        let cell: UITableViewCell = tableView.cellForRow(at: indexPath)!
        address = cell.textLabel!.text!
        searchBar.text = cell.textLabel!.text
    }

我该如何解决?

更新: 看起来它在 searchBar.text = cell.textLabel!.text
之后崩溃了 我添加了 print(searchBar.text!) 并将正确的值打印到控制台

UPD2: 仅当我在搜索栏中输入内容时,应用程序才会崩溃,然后点击屏幕上的某处关闭键盘,然后点击其中一个自动填充单元格。

Class代码:

import UIKit
import Alamofire
import SwiftyJSON

class StreetSelectViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationControllerDelegate
{
    var data: [String] = ["Нет данных"]
    var filtered: [String] = []
    var searchActive : Bool = false

    @IBOutlet weak var cityNameLabel: UILabel!
    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var topSpaceConstraint: NSLayoutConstraint!
    @IBOutlet var gradientBackground: GradientView!

    let segueIdentifier = "ShowStreetSelectSegue"

    //background gradient
    override func viewDidLayoutSubviews()
    {
        self.gradientBackground.create()
    }

    override func viewDidLoad()
    {
        super.viewDidLoad()

        //side menu panGestureRecognizer
        if self.revealViewController() != nil
        {
            self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        }

        tableView.delegate = self
        tableView.dataSource = self
        searchBar.delegate = self
        tableView.tableFooterView = UIView()
        navigationController?.delegate = self

        //search bar settings
        let barImage = UIImage()
        searchBar.setBackgroundImage(barImage, for: .any, barMetrics: .default)
        searchBar.scopeBarBackgroundImage = barImage
        searchBar.tintColor = UIColor.lightGray
        searchBar.setValue("Отмена", forKey:"_cancelButtonText")
        searchBar.showsCancelButton = false

        topSpaceConstraint.constant = self.navigationController!.navigationBar.frame.height + 8

        //network
        let queue = DispatchQueue(label: "com.admin.response-queue", qos: .utility, attributes: [.concurrent])
        URLCache.shared.removeAllCachedResponses()
        Alamofire.request("").validate()
            .responseJSON(
                queue: queue,
                completionHandler: { response in
                    if let JSON = response.result.value
                    {
                        self.data.removeAll()
                        let json = SwiftyJSON.JSON(JSON)
                        print("JSON: \(json)")
                        for (_, object) in json
                        {
                            self.data.append(object.stringValue)
                            print(self.data)
                        }
                    }
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
            }
        )
    }

    override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }

    override func viewWillAppear(_ animated: Bool)
    {
        cityNameLabel.text = cityName
    }

    //MARK: - search bar settings
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
    {
        searchActive = true;
        self.navigationController?.isNavigationBarHidden = true
        topSpaceConstraint.constant = 8
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar)
    {
        searchActive = false;
        self.navigationController?.isNavigationBarHidden = false
    }

    func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
    {
        searchActive = false;
        filtered = data
        tableView.isHidden = false
        tableView.reloadData()
        topSpaceConstraint.constant = 8
    }

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
    {    
        if !searchActive
        {
            searchActive = true
            tableView.reloadData()
        }

        self.searchBar.resignFirstResponder()
        address = searchBar.text!
        performSegue(withIdentifier: "ShowSearchResultsSeque", sender: Any?.self)
    }

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
    {
        filtered = data.filter({ (text) -> Bool in
            let tmp: NSString = text as NSString
            let range = tmp.range(of: searchText, options: NSString.CompareOptions.caseInsensitive)
            return range.location != NSNotFound
        })
        if(filtered.count == 0)
        {
            searchActive = false;
        }
        else
        {
            searchActive = true;
        }

        if searchText.characters.count != 0
        {
            tableView.isHidden = true
        }
        else
        {
            tableView.isHidden = false
        }

        tableView.reloadData()
        topSpaceConstraint.constant = 8
    }

    //MARK: - tableview settings

    func numberOfSections(in tableView: UITableView) -> Int
    {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        if searchActive
        {
            if filtered.count == 0
            {
                return data.count
            }
            else
            {
                return filtered.count
            }
        }
        else
        {
            return data.count
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        if searchActive
        {
            if filtered.count == 0
            {
                cell.textLabel?.text = data.sorted()[indexPath.row]
            }
            else
            {
                cell.textLabel?.text = filtered.sorted()[indexPath.row]
            }
        }
        else
        {
            cell.textLabel?.text = data.sorted()[indexPath.row]
        }
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        let cell: UITableViewCell = self.tableView.cellForRow(at: indexPath)!
        address = cell.textLabel!.text!
        self.searchBar.text = cell.textLabel!.text
        print(searchBar.text!)          
    }

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
    {
        cell.backgroundColor = UIColor.clear
        //text color
        cell.textLabel!.textColor = UIColor.white;
        //cell selection color
        let bgColorView = UIView()
        bgColorView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
        cell.selectedBackgroundView = bgColorView
        tableView.backgroundColor = UIColor.clear
    }                 
}

为什么你在 didSelectRowAt 方法中使用 self.tableView.cellForRow,你可以在 didSelectRowAt 方法中使用你已经在 cellForRowAt 方法中使用的过滤数据源。您可以执行以下操作来实现您的功能。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        if searchActive
        {
            if filtered.count == 0
            {
                address = data.sorted()[indexPath.row]
            }
            else
            {
                address = filtered.sorted()[indexPath.row]
            }
            self.searchBar.text = address
        }         
    }

我不确定为什么,但问题出在 SearchDisplayController。在情节提要中删除它后一切正常