1

Hi I have two arrays and only one array is updating with search bar.. I keep the TitleArray to show in tableView title and detailsArray to show in tableView subtitle.. once I start searching only title following my typing but subtitle nothing change.

@IBOutlet weak var AirportsTableView: UITableView!

var TitleArray = [String]()
var DetailsArray = [String]()

var NumberOfRows = 0


var filteredNamesArray = [String]()
var filteredDetailsArray = [String]()
var resultSearchController = UISearchController!()




**override func viewDidLoad() {
    super.viewDidLoad()**

    // Do any additional setup after loading the view.


    self.resultSearchController = UISearchController(searchResultsController: nil)
    self.resultSearchController.searchResultsUpdater = self

    self.resultSearchController.dimsBackgroundDuringPresentation = false
    self.resultSearchController.searchBar.sizeToFit()
    self.resultSearchController.loadViewIfNeeded()

    self.AirportsTableView.tableHeaderView = self.resultSearchController.searchBar

    self.AirportsTableView.reloadData()


    parseJSON()

}


func parseJSON() {

    if let path = NSBundle.mainBundle().pathForResource("airports", ofType: "json") {
        do {
            let data = try NSData(contentsOfURL: NSURL(fileURLWithPath: path), options: NSDataReadingOptions.DataReadingMappedIfSafe)
            let jsonObj = JSON(data: data)
            if jsonObj != JSON.null {
            // print("jsonData:\(jsonObj)")


                NumberOfRows = jsonObj.count

                for i in 0...NumberOfRows {

                    let City = jsonObj[i]["city"].string as String!
                    let Country = jsonObj[i]["country"].string as String!
                    let Iata = jsonObj[i]["iata"].string as String!
                    let Name = jsonObj[i]["name"].string as String!


                    self.TitleArray.append("\(City) - \(Country) - \(Iata)")
                    self.DetailsArray.append("\(Name)")

                }


            } else {
                print("could not get json from file, make sure that file contains valid json.")
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
    } else {
        print("Invalid filename/path.")
    }

}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/



// MARK: - Table view data source

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections

    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows


    if self.resultSearchController.active

    {
        return self.filteredNamesArray.count

    } else

    {

        return self.TitleArray.count
    }
}


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell?


    if self.resultSearchController.active
    {
        cell!.textLabel?.text = self.filteredNamesArray[indexPath.row]

    } else
    {
        cell!.textLabel?.text = self.TitleArray[indexPath.row]
        cell!.detailTextLabel?.text = self.DetailsArray[indexPath.row]
    }


    return cell!
}

func updateSearchResultsForSearchController(searchController: UISearchController) {

    self.filteredNamesArray.removeAll(keepCapacity: false)

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

    let array = (self.TitleArray as NSArray).filteredArrayUsingPredicate(searchPredicate)

    self.filteredNamesArray = array as! [String]

    self.AirportsTableView.reloadData()
}


// MARK: - Segues

/*

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "AirportDetails" {
        if let indexPath = self.AirportsTableView.indexPathForSelectedRow {
            let airportDetail : Airports = TitleArray[indexPath.row]
            let controller = (segue.destinationViewController as! UINavigationController).topViewController as! AllWaysFlightsViewController
            controller.airportDetail = airportDetail
            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
            controller.navigationItem.leftItemsSupplementBackButton = true
        }
    }
}


*/
Wain
  • 118,658
  • 15
  • 128
  • 151
Ahmed Halim
  • 7
  • 1
  • 5

2 Answers2

1

Instead of using two separate arrays use only one array and populate it with object containing both variables you are using to populate the tableView.

class Address {
    var city: String
    var detail: String

    init(city: String, detail:String) {
        self.city = city
        self.detail = detail
    }
}

Parse your json like this:

for i in 0...NumberOfRows {

                    let City = jsonObj[i]["city"].string as String!
                    let Country = jsonObj[i]["country"].string as String!
                    let Iata = jsonObj[i]["iata"].string as String!
                    let Name = jsonObj[i]["name"].string as String!

                    let city = "\(City) - \(Country) - \(Iata)"

                    let address = Address(city: city, detail: Name)
                    self.TitleArray.append(address)
                    self.filteredNamesArray.append(address)
                }

Filter your title array containing addresses. Your titlearray and filtered array both contains same data for the first time you can refer to the json parsing for this. Here you can use one for filtering and when search bar is empty it user cancel his search you can re-populate your array from the other one.

func updateSearchResultsForSearchController(searchController: UISearchController) {

    self.filteredNamesArray.removeAll(keepCapacity: false)

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

    let array = (self.TitleArray as NSArray).filteredArrayUsingPredicate(searchPredicate)

    self.filteredNamesArray = array as! [Address]

    self.AirportsTableView.reloadData()
}

your tableView logic will be changed accordingly

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows

      return self.filteredNamesArray.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell?

        let address = self.filteredNamesArray[indexPath.row]
        cell!.textLabel?.text = address?.city
        cell!.detailTextLabel?.text = address?.detail

    return cell!
}
Shehzad Ali
  • 1,846
  • 10
  • 16
  • should I add new swift file with address class ? coz I did and show me error with my NS data in parseJSOn function – Ahmed Halim Feb 18 '16 at 12:30
  • yes create a new swift file and add the code mentioned above. – Shehzad Ali Feb 18 '16 at 12:33
  • I made it and with some changes and have only one error in update search results : let array = (self.TitleArray as NSArray).filteredArrayUsingPredicate(searchPredicate) that cannot covert value of type [Address] to type NSArray in coercion – Ahmed Halim Feb 18 '16 at 12:47
  • Declare your arrays like this `var TitleArray = [Address]()` and `var filteredNamesArray = [Address]()` and also change the line your your method `self.filteredNamesArray = array as! [Address]` – Shehzad Ali Feb 18 '16 at 12:52
  • Here is the better solution (check out solution)[http://stackoverflow.com/questions/33030171/cannot-convert-value-of-type-record-to-type-record-in-coercion] – Shehzad Ali Feb 18 '16 at 13:10
  • @AhmedHalim your code will work if you will declare your Address Class as subclass of NSObject. `Class Address : NSObject` – Shehzad Ali Feb 18 '16 at 13:13
  • thanks bro, I left the office will check it sunday. I appreciate your help. – Ahmed Halim Feb 18 '16 at 14:40
  • Thank you it works if I edit your code from : let address = Address(city: city, detail: Name) to let address = Address(city: city, detail: detail) thank you so much :) – Ahmed Halim Feb 21 '16 at 05:09
0

You need to change the way you approach filtering the data so that rather than just apply a predicate you explicitly iterate and check the predicate, if you find a match then you take that item and the corresponding description into your filtered arrays.

Something like:

func updateSearchResultsForSearchController(searchController: UISearchController) {

    self.filteredNamesArray.removeAll(keepCapacity: false)
    self.filteredDetailsArray.removeAll(keepCapacity: false)

    let searchString = searchController.searchBar.text!
    var index = 0

    for title in self.TitleArray
        if title.rangeOfString(searchString).location != NSNotFound {
            self.filteredNamesArray.append(title)
            self.filteredDetailsArray.append(self.DetailsArray[index])
        }

        index += 1
    }

    self.AirportsTableView.reloadData()
}
Wain
  • 118,658
  • 15
  • 128
  • 151
  • Hi, I placed it and changed little bite coz it show me error but still show me (value of type 'range,index.?' has no member 'location' – Ahmed Halim Feb 18 '16 at 12:21