Search code examples
iosjsonswiftuitableviewsearchbar

Q: SearchBar Tableview with JSON File


i need some assistance to add a SearchBar into my ViewController( incl. tableView). I've found some examples to show excisting tableView lines. I want to display titles in the SearchBar out of my JSON file. When i'm typing "Störung"(fault in english) it should display me every title with "Störung" etc.

Everything is working fine exept of the SearchBar, i'm stucked with it...

Here's my code:

import UIKit


class CategoryTableViewController: UITableViewController {
override func prepare(for seque: UIStoryboardSegue, sender: Any?){
    let backItem = UIBarButtonItem()
    backItem.title = "Zurück"
    navigationItem.backBarButtonItem = backItem
}

var categoryNumber: Int?
var answers: [Dictionary<String, AnyObject>]?
var sectionTitle: String?
override func viewDidLoad() {
    super.viewDidLoad()

    tableView.estimatedSectionHeaderHeight = 80
    tableView.sectionHeaderHeight = UITableViewAutomaticDimension

    if let path = Bundle.main.path(forResource: "data", ofType: "json") {
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
            if let jsonResult = jsonResult as? Dictionary<String, AnyObject>, let questions = jsonResult["questions"] as? [Dictionary<String, AnyObject>] {

                for question in questions {
                    if let id = question["id"] as? Int {
                        if(categoryNumber! == id)
                        {
                            answers = question["answers"] as? [Dictionary<String, AnyObject>]
                            sectionTitle = question["title"] as? String
                        }
                    }
                }

            }
        } catch {

        }
    }


}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}



override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sectionTitle
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return UITableViewAutomaticDimension
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 100))

    let label = UILabel()
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.frame = CGRect.init(x: 5, y: 5, width: headerView.frame.width-10, height: headerView.frame.height-10)
    label.text = sectionTitle

    headerView.addSubview(label)

    return headerView
}


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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return answers!.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! CategoryTableViewCell

    let answer = answers![indexPath.row]
    cell.categoryLabel.text = answer["title"] as? String

    let type = answer["type"] as! String
    if(type == "question") {
        cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
    }


    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let answer = answers![indexPath.row]
    let type = answer["type"] as! String
    if(type == "question") {
        let link = answer["link"] as! Int
        if let viewController2 = self.storyboard?.instantiateViewController(withIdentifier: "CategoryTableViewController") {
            let categoryTableViewController = viewController2 as! CategoryTableViewController
            categoryTableViewController.categoryNumber = link
            self.navigationController?.pushViewController(viewController2, animated: true)
        }
    } else {
        let link = answer["link"] as! String
        if let viewController2 = self.storyboard?.instantiateViewController(withIdentifier: "PDFViewController") {
            let pdfViewController = viewController2 as! PDFViewController
            pdfViewController.pdfName = link
            self.navigationController?.pushViewController(viewController2, animated: true)
        }
    }

}

}

This is a bit of my JSON File:

{
    "id": 50,
    "title": "Sie brauchen Hilfe bei der Fehlersuche/Fehlerbehebung. Wobei brauchen Sie Hilfe?",
    "answers": [
        {
            "type": "question",
            "title": "Busstörung",
            "link": 60
        },
        {
            "type": "pdf",
            "title": "Ein Modul lässt sich nicht mehr auslesen?",
            "link": "205.pdf"
        },
        {
            "type": "pdf",
            "title": "Modul ersetzt, wie programmiere ich es?",
            "link": "206.pdf"
        },

This is my ViewController : https://www.imagebanana.com/s/1193/29VvUoAs.html

Can someone help me please? Thanks in advance!!


Solution

  • First, you need to define a dictionary for searched answers:

    var filteredAnswers: [Dictionary<String, AnyObject>]?
    

    Then, define a function when user tap search button or search textfield:

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar){
    
            self.filteredAnswers.removeAll()
            if (searchBar.text?.isEmpty)! {
                self.filteredAnswers=self.answers
            } else {
                if self.answers.count > 0 {
                    for i in 0...self.answers.count - 1 {
                        let answer = self.answers[i] as [Dictionary<String, AnyObject>]
                        if answer.title.range(of: searchBar.text!, options: .caseInsensitive) != nil {
                            self.filteredAnswers.append(answer)
                        }
                    }
                }
            }
            tableView.reloadData();
            tableView.reloadInputViews();
            searchBar.resignFirstResponder()
    }
    

    After this configuration, you need to change let answer = answers![indexPath.row] to let answer = filteredAnswers![indexPath.row] in cellForRowAt function.