Tableview SearchBar For Json Data

2019-08-19 01:00发布

问题:

I'm making an app that parses JSON data & populates a tableview. In this app i want to make a SearchBar to search the id's. Everything is fine with parsing and populating the tableview but I am having problem with the searching. When I run the app I am gettin the following error: terminating with uncaught exception of type NSException

I have two arrays, first one is the main one and the other one is filtered one.

Requirement: I want to search array by "DesenNo" which i declared in my model.

Here are my codes:

ViewController:

import UIKit import Foundation import os.log

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating, HomeModelProtocol {

//Properties
var feedItems: NSArray = NSArray()
var detailViewController: detailsVC? = nil
var searchActive : Bool = false
var filteredData:[String] = []
    var resultSearchController:UISearchController!
@IBOutlet weak var listTableView: UITableView!

@IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
    super.viewDidLoad()

    resultSearchController = UISearchController(searchResultsController: nil)

    resultSearchController.searchResultsUpdater = self

    resultSearchController.hidesNavigationBarDuringPresentation = false

    resultSearchController.dimsBackgroundDuringPresentation = false

    resultSearchController.searchBar.searchBarStyle = UISearchBarStyle.prominent

    resultSearchController.searchBar.sizeToFit()

    self.listTableView.tableHeaderView = resultSearchController.searchBar

    self.listTableView.dataSource = self

    let homeModel = HomeModel()
    homeModel.delegate = self
    homeModel.downloadItems()

}


func itemsDownloaded(items: NSArray) {

    feedItems = items
    self.listTableView.reloadData()
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if resultSearchController.isActive {
        return filteredData.count
    }
    else {
        return feedItems.count
    }

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Retrieve cell

    let cellIdentifier: String = "BasicCell"
    let myCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyTableCell
    // Get the location to be shown
    // Get references to labels of cell
     //Label1
    if resultSearchController.isActive {
        let item: LocationModel = feedItems[indexPath.row] as! LocationModel
        let desenNoToString = item.DesenNo

        let desenString = "\(desenNoToString)"
        let regex = try! NSRegularExpression(pattern:"\"(.*)\"")
        if let match = regex.firstMatch(
            in: desenString, range:NSMakeRange(0,desenString.utf16.count)) {
            let result = (desenString as NSString).substring(with: match.range(at:1))
            myCell.label1!.text = result
        }


        //Label2
        let dolarToString = item.Dolar
        let dolarString = "\(dolarToString)"
        if let match = regex.firstMatch(
            in: dolarString, range:NSMakeRange(0,dolarString.utf16.count)) {
            let result = (dolarString as NSString).substring(with: match.range(at:1))
            myCell.label2!.text = result
        }

        //Label3
        let zeminToString = item.Zemin
        let zeminString = "\(zeminToString)"
        if let match = regex.firstMatch(
            in: zeminString, range:NSMakeRange(0,zeminString.utf16.count)) {
            let result = (zeminString as NSString).substring(with: match.range(at:1))
            myCell.label3!.text = result
        }

        //Label4
        let renkToString = item.Renk
        let renkString = "\(renkToString)"
        if let match = regex.firstMatch(
            in: renkString, range:NSMakeRange(0,renkString.utf16.count)) {
            let result = (renkString as NSString).substring(with: match.range(at:1))
            myCell.label4!.text = result
        }

        //Label5
        let enToString = item.En
        let enString = "\(enToString)"
        if let match = regex.firstMatch(
            in: enString, range:NSMakeRange(0,enString.utf16.count)) {
            let result = (enString as NSString).substring(with: match.range(at:1))
            myCell.label5!.text = result
        }

        //Label6
        let euroToString = item.Euro
        let euroString = "\(euroToString)"
        if let match = regex.firstMatch(
            in: euroString, range:NSMakeRange(0,euroString.utf16.count)) {
            let result = (euroString as NSString).substring(with: match.range(at:1))
            myCell.label6!.text = result
        }
    }else {
        let item: LocationModel = feedItems[indexPath.row] as! LocationModel
        let desenNoToString = item.DesenNo

        let desenString = "\(desenNoToString)"
        let regex = try! NSRegularExpression(pattern:"\"(.*)\"")
        if let match = regex.firstMatch(
            in: desenString, range:NSMakeRange(0,desenString.utf16.count)) {
            let result = (desenString as NSString).substring(with: match.range(at:1))
            myCell.label1!.text = result
        }


        //Label2
        let dolarToString = item.Dolar
        let dolarString = "\(dolarToString)"
        if let match = regex.firstMatch(
            in: dolarString, range:NSMakeRange(0,dolarString.utf16.count)) {
            let result = (dolarString as NSString).substring(with: match.range(at:1))
            myCell.label2!.text = result
        }

        //Label3
        let zeminToString = item.Zemin
        let zeminString = "\(zeminToString)"
        if let match = regex.firstMatch(
            in: zeminString, range:NSMakeRange(0,zeminString.utf16.count)) {
            let result = (zeminString as NSString).substring(with: match.range(at:1))
            myCell.label3!.text = result
        }

        //Label4
        let renkToString = item.Renk
        let renkString = "\(renkToString)"
        if let match = regex.firstMatch(
            in: renkString, range:NSMakeRange(0,renkString.utf16.count)) {
            let result = (renkString as NSString).substring(with: match.range(at:1))
            myCell.label4!.text = result
        }

        //Label5
        let enToString = item.En
        let enString = "\(enToString)"
        if let match = regex.firstMatch(
            in: enString, range:NSMakeRange(0,enString.utf16.count)) {
            let result = (enString as NSString).substring(with: match.range(at:1))
            myCell.label5!.text = result
        }

        //Label6
        let euroToString = item.Euro
        let euroString = "\(euroToString)"
        if let match = regex.firstMatch(
            in: euroString, range:NSMakeRange(0,euroString.utf16.count)) {
            let result = (euroString as NSString).substring(with: match.range(at:1))
            myCell.label6!.text = result
        }
    }


    return myCell
}
func updateSearchResults(for searchController: UISearchController) {

    if searchController.isActive {

        filteredData.removeAll(keepingCapacity: false)
        let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text!)
        let array = (feedItems as NSArray).filtered(using: searchPredicate)
        filteredData = array as! [String]
        listTableView.reloadData()

    }
    else {

        filteredData.removeAll(keepingCapacity: false)

        filteredData = feedItems as! [String]

        listTableView.reloadData()

    }


}

}

LocationModel.Swift

import UIKit

class LocationModel: NSObject {

//properties

var DesenNo: String?
var Dolar: String?
var Zemin: String?
var En: String?
var Euro: String?
var Renk: String?




//empty constructor

override init()
{

}

//construct with @name, @address, @latitude, and @longitude parameters

init(DesenNo: String, Dolar: String, Zemin: String, En: String, Euro: String, Renk: String) {

    self.DesenNo = DesenNo
    self.Dolar = Dolar
    self.Zemin = Zemin
    self.En = En
    self.Euro = Euro
    self.Renk = Renk


}


//prints object's current state

override var description: String {
    return "Desen: \(DesenNo), Dolar: \(Dolar), Zemin: \(Zemin), Renk: \(Renk), En: \(En), Euro: \(Euro) "

}

}

HomeModel.Swift

import UIKit

protocol HomeModelProtocol: class { func itemsDownloaded(items: NSArray) }

class HomeModel: NSObject {

//properties

weak var delegate: HomeModelProtocol!

let urlPath = "http://aktul.com/den.php" //this will be changed to the path where service.php lives

func downloadItems() {

    let url: URL = URL(string: urlPath)!
    let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)

    let task = defaultSession.dataTask(with: url) { (data, response, error) in

        if error != nil {
            print("Failed to download data")
        }else {
            print("Data downloaded")
            self.parseJSON(data!)
        }

    }

    task.resume()
}

func parseJSON(_ data:Data) {

    var jsonResult = NSArray()

    do{
        jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray

    } catch let error as NSError {
        print(error)

    }

    var jsonElement = NSDictionary()
    let urunler = NSMutableArray()

    for i in 0 ..< jsonResult.count
    {

        jsonElement = jsonResult[i] as! NSDictionary

        let urun = LocationModel()

        //the following insures none of the JsonElement values are nil through optional binding
        if let desen = jsonElement["DesenNo"] as? String,
            let dolar = jsonElement["Dolar"] as? String,
            let zemin = jsonElement["Zemin"] as? String,
            let renk = jsonElement["Renk"] as? String,
            let en = jsonElement["En"] as? String,
            let euro = jsonElement["Euro"] as? String


            //let longitude = jsonElement["Longitude"] as? String
        {

            urun.DesenNo = desen
            urun.Dolar = dolar
            urun.Zemin = zemin
            urun.Renk = renk
            urun.En = en
            urun.Euro = euro
        }

        urunler.add(urun)
    }


    DispatchQueue.main.async(execute: { () -> Void in

        self.delegate.itemsDownloaded(items: urunler)
    })
}

}

回答1:

Update with following code in updatesearchResults function

func updateSearchResults(for searchController: UISearchController) {

        if searchController.isActive {

            filteredData.removeAll(keepingCapacity: false)
            let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text!)

            let array = self.feedItems.filter { searchPredicate.evaluate(with: ($0 as! LocationModel).DesenNo) }

            let filterArray = array.map {($0 as! LocationModel).DesenNo}
            filteredData = filterArray as! [String]
            tabelView.reloadData()

        }
        else {
            filteredData.removeAll(keepingCapacity: false)
            tabelView.reloadData()
        }
    }