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)
})
}
}
Update with following code in
updatesearchResults
function