1

Hey i have a tableview with a search bar on top of it. i request a remote rest-api with the search-term. The searchbar func looks like this (according to this post: How to throttle search (based on typing speed) in iOS UISearchBar?)

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.searchTeams), object: nil)
    self.perform(#selector(self.searchTeams), with: nil, afterDelay: 0.3)
}

The searchTeams-Func looks like this, it calls the asynchrony function loadingJSON with a completion handler:

loadingJSON("APIPATH", postString:"STRING") {
    parseJSON in

        if(String(describing: parseJSON) == "-1"){
            print("No Internet")
        } else {
            if let teams = parseJSON["teams"] as? [[String: AnyObject]] {
                self.teams.removeAll()

                for team in teams {
                   //Parse data
                }
                self.tableView.reloadData()

            }
        }
}

This works almost perfectly. But sometimes the app crashes in the cellForRowAt-indexPath-Methode in following line:

teamSearchResultsCell.TeamNameLable.text = self.teams[indexPath.row].teamName

The indexPath.row = 0 but the teams array is empty. So i think is occurs if the user taps the cell right in the moment when the function cleared the array but hasn't reloaded the tableview yet. Any ideas to solve this?

EDITED: loadingJSON-func for who's interested:

func loadingJSON(_ link:String, postString:String, completionHandler: @escaping (_ JSONObject: AnyObject) -> ()) {
    if(Reachability.isConnectedToNetwork() == false){
        completionHandler("-1" as AnyObject)
        return
    }

    let request = NSMutableURLRequest(url: URL(string: FinalVars.getMobileRequestURL() + link)!)
    request.httpMethod = "POST"
    request.timeoutInterval = FinalVars.getRequestTimeoutIntervalInSeconds() //=7 Set Timeout in Seconds
    request.httpBody = postString.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
        guard error == nil && data != nil else {
            //TimeOutReached --> No Network Connection
            print("error=\(String(describing: error))")

            DispatchQueue.main.async(execute: {
                completionHandler("-1" as AnyObject)
            })
            return
        }

        if let httpStatus = response as? HTTPURLResponse , httpStatus.statusCode != 200 {           // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(String(describing: response))")
        }

        //JSON successfull
        do {

            let parseJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)

            DispatchQueue.main.async(execute: {
                completionHandler(parseJSON as AnyObject)
            });


        } catch let error as NSError {
            print("Failed to load: \(error.localizedDescription)")

        }
    }
    task.resume() 
}
Marco Weber
  • 829
  • 10
  • 19
  • What is `loadingJSON`? Can you show the code? – Andreas Oetjen Jan 29 '18 at 12:57
  • updated my question ... – Marco Weber Jan 29 '18 at 13:20
  • So, from my point of view, there shouldn't be multithreading problems in your code. But maybe you should ensure this, by `NSLog`ing some output inside the completion closure as well as in `tableView(_:cellForRowAt:)`, just to make sure that they run on the same thread. I suppose `tableView(_:numberOfRowsInSection:)` returns `self.teams.count`, correct? – Andreas Oetjen Jan 29 '18 at 13:41

1 Answers1

0

You should just have a line to make it safe...

if teams.count > 0  { .. do your stuff ... } else { .. do nothing - there are no teams .. }

Assuming your teams array is populated shortly thereafter, the above line will help make sure everything is okay until the network response answers back with your data, then everything will be dandy. Hope this helps.

escullz
  • 103
  • 1
  • 10
  • done it, but didn't worked. The app still crashed sometimes. I've done it with a timer, link in this answer: https://stackoverflow.com/a/38987761/6003494 – Marco Weber Feb 20 '18 at 11:57