search bar avec plusieurs critère

easydeasyd Membre
mars 2017 modifié dans API UIKit #1

Bonjour tous le monde,


 


Je sous sollicite pour un problème d'affichage, j'ai un search bar avec plusieurs critère de recherche.


 


Mais cela s'affiche sur plusieurs ligne et comprend pas pourquoi.


 


Je pense que je dois faire un  cela est il UITableViewCell obligé ?


 


voilà  mon code :



import UIKit

class SearchViewController: UIViewController, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate
{

var maList = [String]()
var maFilteredList = [String]()
var price: [String] = []

@IBOutlet var tbl: UITableView!

override func viewDidLoad()
{
super.viewDidLoad()

let url=URL(string:"http://serveur/api/json_search.php")

do {
let allData = try Data(contentsOf: url!)
let all = try JSONSerialization.jsonObject(with: allData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = all["contacts"] {
for index in 0...arrJSON.count-1 {

let JSON = arrJSON[index] as! [String : AnyObject]
print(JSON)

maList.append(JSON["produit"] as! String)
maList.append(JSON["prix"] as! String)
maList.append(JSON["autre"] as! String)
maList.append(JSON["details"] as! String)


}
}

self.tbl.reloadData()
}
catch {

}

}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.maFilteredList.count
} else {
return self.maList.count
}
}

func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tbl.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

var name : String!
if tableView == self.searchDisplayController!.searchResultsTableView {
name = maFilteredList[indexPath.row]
} else {
name = maList[indexPath.row]
}

cell.textLabel?.text = name

return cell
}

func filterTableViewForEnterText(_ searchText: String) {
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchText)

let array = (self.maList as NSArray).filtered(using: searchPredicate)
self.maFilteredList = array as! [String]
self.tbl.reloadData()
}

func searchDisplayController(_ controller: UISearchDisplayController, shouldReloadTableForSearch searchString: String?) -> Bool {
self.filterTableViewForEnterText(searchString!)
return true
}

func searchDisplayController(_ controller: UISearchDisplayController,
shouldReloadTableForSearchScope searchOption: Int) -> Bool {
self.filterTableViewForEnterText(self.searchDisplayController!.searchBar.text!)
return true
}
}

j'a cela qui ce présente comme ceci :


 


vin

________________


rouge, de qualité


_________________


10$


_________________


autre


_________________


 


et cela devrais être comme cela :


 


vin


rouge, de qualité


10$


autre


_________________


 

Et de plus quant je veux faire le passage de mon choix  (storyboard) au details cela ne fonctionne pas.


 


Merci de votre aide,


Réponses

  • LarmeLarme Membre

    let allData = try Data(contentsOf: url!)

    => Beurk. Appel à  un WebService fait de manière synchrone et sur le main thread.



    maList.append(JSON["produit"] as! String)
    maList.append(JSON["prix"] as! String)
    maList.append(JSON["autre"] as! String)
    maList.append(JSON["details"] as! String)

    Là , tu crées une liste avec à  chaque fois un item qui n'a aucun sens par rapport au précédent.


    Créer un objet ou un struct qui a un sens avec ces 4 données, un objet "MonProduit", avec 4 propriétés : nom, prix, details, autre.


     


     


    Donc forcément, quand tu fais ça :



    cell.textLabel?.text = name

    ça fait 4 cellules...


     


    Profites-en pour créer une custom UITableViewCell qui se chargera de pouvoir afficher en tant qu'une seule cellule les 4 données.


     


    Ensuite, sur ton filtre de search, filter sur chaque properties ou seulement celles qui t'intéresse, car actuellement, avec l'exemple que tu as donné, si tu cherches "vin", tu n'auras aucune des autres infos comme son prix, etc.

  • easydeasyd Membre
    mars 2017 modifié #3

    Bonjour me voilà ,


    J'ai avancer sur mon code comme tu ma dit, cela fonctionne à  peu près j'ai bien la liste de mes objets.



     


    Quant je fait une recherche cela envoyé bien ma requête en JSON mais je résultat ne s'affiche pas.


    J'ai vérifier mes requête, j'ai bien sur les logs apache ma requête, et sur mon terminal Xcode la requête répond bien au niveau de nom serveur.



     


    Je comprend pas pourquoi cela ne s'affiche pas.



     


    Pouvez-vous m'aider merci a vous, voilà  mon code :

     


     


    RequestManager :



    import Foundation
    import Alamofire
    import SwiftyJSON

    class RequestManager {

    var searchResults = [JSON]()
    var hasMore = false

    func search(_ searchText: String) {

    Alamofire.request("http://serveur/api/liste.php?recherche=\(searchText)").responseJSON { response in
    if let results = response.result.value as? [String:AnyObject] {
    let items = JSON(results["search"]!).arrayValue

    self.searchResults += items

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)
    }

    }
    }

    func getNextPage(_ searchText: String) {
    search(searchText)
    }

    func resetSearch() {
    searchResults = []
    }
    }

    Mon TableViewController :



    import UIKit
    import SwiftyJSON
    import Alamofire


    class SearchViewController: UITableViewController {


    @IBOutlet var menuButton:UIBarButtonItem!
    @IBOutlet var extraButton:UIBarButtonItem!

    var ui_rs = String()


    var personList:[[String:AnyObject]] = []

    var searchResults = [JSON]() {
    didSet {
    tableView.reloadData()
    }
    }

    var validatedText: String {
    return searchController.searchBar.text!.replacingOccurrences(of: " ", with: "").lowercased()
    }

    let searchController = UISearchController(searchResultsController: nil)
    let requestManager = RequestManager()

    override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchBar.delegate = self
    searchController.dimsBackgroundDuringPresentation = false
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.searchBar.placeholder = "SEARCH"
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar
    searchController.searchBar.sizeToFit()

    NotificationCenter.default.addObserver(self, selector: #selector(SearchViewController.updateSearchResults), name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)

    Alamofire.request("http://serveur/api/liste_p.php")
    .validate()
    .responseJSON { (response) in
    if response.result.isSuccess {
    self.personList = response.result.value as! [[String:AnyObject]]
    self.tableView.reloadData()
    } else {
    print(response.result.error!)
    }


    }

    if revealViewController() != nil {

    menuButton.target = revealViewController()
    menuButton.action = #selector(SWRevealViewController.revealToggle(_:))

    revealViewController().rightViewRevealWidth = 220
    extraButton.target = revealViewController()
    extraButton.action = #selector(SWRevealViewController.rightRevealToggle(_:))

    view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    }
    }

    func updateSearchResults() {
    searchResults = requestManager.searchResults
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:SearchNewsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SearchNewsTableViewCell
    let person:[String:AnyObject] = personList[indexPath.row]

    cell.display(person: person)

    if indexPath.row == searchResults.count - 10 {
    if requestManager.hasMore {
    requestManager.getNextPage(validatedText)
    }
    }

    return cell
    }

    deinit {
    NotificationCenter.default.removeObserver(self)
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchBar.setShowsCancelButton(false, animated: true)
    }

    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    self.view.endEditing(true)
    searchBar.setShowsCancelButton(false, animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
    if let cell = sender as? UITableViewCell {
    if let indexPath = self.tableView.indexPath(for: cell) {
    let selectedPerson = personList[indexPath.row]

    let personViewController:SearchDetailFoTableViewController = segue.destination as! SearchDetailFoTableViewController
    personViewController.persons = selectedPerson

    }

    }
    }
    }
    }

    extension SearchViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

    requestManager.resetSearch()
    updateSearchResults()
    requestManager.search(validatedText)
    }
    }

    Merci de votre aide,


  • Joanna CarterJoanna Carter Membre, Modérateur
    mars 2017 modifié #4

    Tu as mis les breakpoints dans ton code pour vérifier qu'il execute ?


  • LarmeLarme Membre

    Tu mélanges l'utilisation de searchResultspersonList.


    Il faut que tu sépares bien le cas quand c'est personList qui doit définir le nombre de cellules, et la manière dont sont remplies les cellules, et quand c'est le travail de searchResult.


  • easydeasyd Membre

    Merci de vos aide,


     


    A avance a petit pas mais surement.


     


    Je suis arriver a rafraichie ma recherche a chaque requête.


    Cela me donne toujours la 1er ligne pas plus, le count fonctionne bien.


    Cela ne s'initialise pas.



    import UIKit
    import SwiftyJSON
    import Alamofire


    class SearchViewController: UITableViewController {


    @IBOutlet var menuButton:UIBarButtonItem!
    @IBOutlet var extraButton:UIBarButtonItem!

    var ui_rs = String()


    var personList:[[String:AnyObject]] = []

    var searchResults = [JSON]() {
    didSet {
    tableView.reloadData()
    }
    }

    var validatedText: String {
    return searchController.searchBar.text!.replacingOccurrences(of: " ", with: "").lowercased()
    }

    let searchController = UISearchController(searchResultsController: nil)
    let requestManager = RequestManager()

    override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchBar.delegate = self
    searchController.dimsBackgroundDuringPresentation = false
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.searchBar.placeholder = "SEARCH"
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar
    searchController.searchBar.sizeToFit()

    NotificationCenter.default.addObserver(self, selector: #selector(SearchViewController.updateSearchResults), name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)

    Alamofire.request("http://serveur/api/liste_p.php")
    .validate()
    .responseJSON { (response) in
    if response.result.isSuccess {
    self.personList = response.result.value as! [[String:AnyObject]]
    self.tableView.reloadData()
    } else {
    print(response.result.error!)
    }
    }

    if revealViewController() != nil {

    menuButton.target = revealViewController()
    menuButton.action = #selector(SWRevealViewController.revealToggle(_:))

    revealViewController().rightViewRevealWidth = 220
    extraButton.target = revealViewController()
    extraButton.action = #selector(SWRevealViewController.rightRevealToggle(_:))

    view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    }
    }

    func updateSearchResults() {
    searchResults = requestManager.searchResults
    }
        override func numberOfSections(in tableView: UITableView) -> Int {
            
            return 1
        }
        
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            
            if searchResults.count != 1 {
                
                return personList.count
                
            }else{
                
                return searchResults.count
            
            }
        }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:SearchNewsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SearchNewsTableViewCell
    let person:[String:AnyObject] = personList[indexPath.row]

    cell.display(person: person)

    if indexPath.row == searchResults.count - 10 {
    if requestManager.hasMore {
    requestManager.getNextPage(validatedText)
    }
    }

    return cell
    }

    deinit {
    NotificationCenter.default.removeObserver(self)
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchBar.setShowsCancelButton(false, animated: true)
    }

    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    self.view.endEditing(true)
    searchBar.setShowsCancelButton(false, animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
    if let cell = sender as? UITableViewCell {
    if let indexPath = self.tableView.indexPath(for: cell) {
    let selectedPerson = personList[indexPath.row]

    let personViewController:SearchDetailFoTableViewController = segue.destination as! SearchDetailFoTableViewController
    personViewController.persons = selectedPerson

    }

    }
    }
    }
    }

    extension SearchViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

    requestManager.resetSearch()
    updateSearchResults()
    requestManager.search(validatedText)
    }
    }

    Merci de votre aide, j'avance bien.


  • easydeasyd Membre

    Bonjour tous le monde,


     


    J'ai un problème, cela fonctionne mais j'ai toujours la 1er ligne, ne comprend pas command modifié cette celà .


     


    je cherche un produit cuisine, dans ma BDD il y a deux cuisines et il m'affiche le 1er produit qui n'est pas une cuisine et la deuxième produit lui est bien une cuisine. 


     


    let person:[String:AnyObject] = personList[indexPath.row]


     


    comme la j'ai un erreur


     


    let person:[String:AnyObject] = searchResults[indexPath.row]


     


    j'ai cette erreur : Cannot convert value of type 'JSON' to specified type '[String : AnyObject]'


     


    Merci de votre aide,

  • LarmeLarme Membre

    Réfléchis à  comment tu as défini personList et searchResults :



    var personList:[[String:AnyObject]] = []
    var searchResults = [JSON]()

    Qu'est-ce qui garantit que JSON est égal à  String:AnyObject ?

  • easydeasyd Membre
    mars 2017 modifié #9

    je n'y arrive vraiment pas je comprend plus rien.

  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu as défini searchResults comme [JSON] (crray de JSON) et personList comme String : AnyObject array de dictionnaire. Du coup, c'est impossible d'assigner un JSON dans une référence pour un dictionnaire.


  • Bonjour,


     


    Je n'y arrive pas je comprend pas tous, et cela m'agace vraiment.


     


    j'ai changer mon code je veux plus utiliser pas faciliter personList comme String : AnyObject mais JSON.


    Voilà  mon code :



    import UIKit
    import SwiftyJSON
    import Alamofire


    class SearchViewController: UITableViewController {


    @IBOutlet var menuButton:UIBarButtonItem!
    @IBOutlet var extraButton:UIBarButtonItem!

    var ui_rs = String()

    //var searchResults:[[String:AnyObject]] = []

    var searchResults = [JSON]() {
    didSet {
    tableView.reloadData()
    }
    }

    var validatedText: String {
    return searchController.searchBar.text!.replacingOccurrences(of: " ", with: "+").lowercased()
    }

    let searchController = UISearchController(searchResultsController: nil)
    let requestManager = RequestManager()

    override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchBar.delegate = self
    searchController.dimsBackgroundDuringPresentation = false
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.searchBar.placeholder = "SEARCH"
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar
    searchController.searchBar.sizeToFit()

    NotificationCenter.default.addObserver(self, selector: #selector(SearchViewController.updateSearchResults), name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)

    Alamofire.request("http://serveur/api/liste_annonces.php")
    .validate()
    .responseJSON { (response) in
    if response.result.isSuccess {

    self.searchResults = response.result.value as! [JSON]
    self.tableView.reloadData()


    } else {

    print(response.result.error!)
    }
    }

    if revealViewController() != nil {

    menuButton.target = revealViewController()
    menuButton.action = #selector(SWRevealViewController.revealToggle(_:))

    revealViewController().rightViewRevealWidth = 220
    extraButton.target = revealViewController()
    extraButton.action = #selector(SWRevealViewController.rightRevealToggle(_:))

    view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    }



    }

    func updateSearchResults() {
    searchResults = requestManager.searchResults
    }

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

    return 1
    }

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

    return searchResults.count

    }

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

    //let person:[String:AnyObject] = searchResults[indexPath.row]

    //cell.display(person: person)


    return cell
    }

    deinit {
    NotificationCenter.default.removeObserver(self)
    }


    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchBar.setShowsCancelButton(false, animated: true)
    }

    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    self.view.endEditing(true)
    searchBar.setShowsCancelButton(false, animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
    if let cell = sender as? UITableViewCell {
    if let indexPath = self.tableView.indexPath(for: cell) {
    let selectedPerson = [searchResults[indexPath.row]] as [JSON]

    let personViewController:SearchDetailFoTableViewController = segue.destination as! SearchDetailFoTableViewController
    personViewController.persons = selectedPerson

    }

    }
    }
    }
    }

    extension SearchViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

    requestManager.resetSearch()
    updateSearchResults()
    requestManager.search(validatedText)
    }
    }

    J'ai une erreur de ce type a cette ligne :


     


    personViewController.persons = selectedPerson


     


    Cannot assign value of type '[JSON]' to type '[String : Any]?'


     


    Et je n'y arrive pas.


     


    Merci de vos aide,



  • Bonjour,


     


    Je n'y arrive pas je comprend pas tous, et cela m'agace vraiment.


     


    j'ai changer mon code je veux plus utiliser pas faciliter personList comme String : AnyObject mais JSON.


    Voilà  mon code :


    J'ai une erreur de ce type a cette ligne :


     


    personViewController.persons = selectedPerson


     


    Cannot assign value of type '[JSON]' to type '[String : Any]?'


     


    Et je n'y arrive pas.


     


    Merci de vos aide,




    Parce que dans SearchDetailFoTableViewController, persons est défini comme [String:Any]? et pas [JSON].


     


    Il faut comprendre cette erreur qui est basique : Cannot assigne value of type typeA to typeB ou Could not cast value of type typeA to typeB qui sont liées.


     


    Tu dis :


    Hey ! La propriété Persons de SearchDetailFoTableViewController sera du un objet défini comme étant [String:Any]?


    Et après, tu lui donnes un objet [JSON]


    Du coup le compilateur n'est pas dupe, il comprend qu'ils sont différents.


     


    Imagine ceci :


    [JSON] = Chien


    [String:Any] = Chat


    SearchDetailFoTableViewController : Famille fan de chat


    Persons = La place du chat dans la famille.


     


    Là , c'est comme si tu essayais de refiler un chien à  la famille qui est tout préparé pour avoir un chat. Euh, y'a erreur sur la marchandise.

  • easydeasyd Membre
    mars 2017 modifié #13

    Merci ça fonctionne, mais quant c'est null cela plante.



    import UIKit
    import Alamofire
    import SwiftyJSON

    class RequestManager {

    var searchResults:[[String:AnyObject]] = []
    var hasMore = false

    func search(_ searchText: String) {

    Alamofire.request("http://serveur/liste.php?recherche=\(searchText)").responseJSON { response in
    if let results = response.result.value as? [String:Any] {

    let items = results["search"]
    self.searchResults = items as! [[String : AnyObject]]

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)
    }
    }
    }

    func getNextPage(_ searchText: String) {
    search(searchText)
    }

    func resetSearch() {
    searchResults = []
    }
    }


    A ce niveau :


              


    self.searchResults = items as! String : AnyObject


     


    Merci Larme j'avance bien là , avec ces explications,

     


  • J'ai réussi a ce que ça ne plante plus quant c'est null.


     


    Là  je vais voir pour intégrer un message d'erreur quant c'est NULL.


  • Joanna CarterJoanna Carter Membre, Modérateur
    mars 2017 modifié #15

    Tu as toujours les erreurs parce que tu ne prends pas les précautions.



    class RequestManager
    {
    var searchResults = [[String : Any]]()

    var hasMore = false

    func search(_ searchText: String)
    {
    Alamofire.request("http://serveur/liste.php?recherche=\(searchText)").responseJSON
    {
    response in

    guard let response.result.isSuccess else
    {
    // montrer erreur

    return
    }

    if let results = response.result.value as? [String:Any],
    let items = results["search"] as? [[String : Any]]
    {
    self.searchResults = items

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "searchResultsUpdated"), object: nil)
    }
    }
    }
    }

    Et, comme on t'a dit, plusieurs fois, arrêtes-toi d'utiliser les '!' !!!


Connectez-vous ou Inscrivez-vous pour répondre.