2016-02-29 23 views
10

L'app mostra un elenco di parti di automobili (parte dell'automobile, tipo, anno, paese) che sta funzionando in una vista tabella con una barra di ricerca.Aggiunta di Scope Bar in swift

Ora ho deciso di aggiungere una barra di ambito per filtrare i risultati, e sono sicuro che ho incasinato il codice. Ci sono molti errori nelle righe per aggiungere scopeBar. Sono le ultime 20 righe, dopo il commento //ScopeBar try, oltre a quest'ultima righe ho aggiunto un codice nello viewDidLoad() per mostrare i titoli che voglio.

Cosa sto sbagliando? Qualsiasi aiuto è più che benvenuto, sto cercando di risolvere questo problema già da 2 giorni senza fortuna.

import UIKit 
import CoreData 

class DictionaryTableViewController: UITableViewController, NSFetchedResultsControllerDelegate, UISearchResultsUpdating 
{ 

    var searchController:UISearchController! 
    var searchResults:[Dictionary] = [] 

    private var dictionaryItems:[Dictionary] = [] 

    private var cockpitDict = [String: [Dictionary]]() 
    var sectionTitles = [String]() 

    var fetchResultController:NSFetchedResultsController! 

    override func viewDidLoad() { 
     super.viewDidLoad() 


     // ScopeBar Try 
     searchController.searchBar.scopeButtonTitles = ["All", "type", "year", "country"] 
     tableView.tableHeaderView = searchController.searchBar 



     // Load menu items from database 
     if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext { 

      let fetchRequest = NSFetchRequest(entityName: "DictionaryEntity") 
      do { 
       dictionaryItems = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Dictionary] 
      } catch { 
       print("Failed to retrieve record") 
       print(error) 
      } 
     } 

     searchController = UISearchController(searchResultsController: nil) 
     tableView.tableHeaderView = searchController.searchBar 
     searchController.searchResultsUpdater = self 
     searchController.dimsBackgroundDuringPresentation = false 
     searchController.searchBar.placeholder = "Search ..." 

     navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: 
      .Plain, target: nil, action: nil) 

     // Enable self sizing cells 
     tableView.estimatedRowHeight = 100.0 
     tableView.rowHeight = UITableViewAutomaticDimension 


     createCockpitDict() 
    } 

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

    func createCockpitDict(){ 

     for item in dictionaryItems { 

      guard let word = item.word else { 
       break 
      } 

      // Get the first letter of the word and build the dictionary 
      let wordKey = word.substringToIndex(word.startIndex.advancedBy(1)) 
      if var cockpitItems = cockpitDict[wordKey] { 
       cockpitItems.append(item) 
       cockpitDict[wordKey] = cockpitItems 
      } else { 
       cockpitDict[wordKey] = [item] 
      } 
     } 

     // Get the section titles from the dictionary's keys and sort them in ascending order 
     sectionTitles = [String](cockpitDict.keys) 
     sectionTitles = sectionTitles.sort({ $0 < $1 }) 
    } 

// create a standard way to get a Dictionary from a index path 
    func itemForIndexPath (indexPath: NSIndexPath) -> Dictionary? { 
     var result: Dictionary? = nil 

     if searchController.active { 
      result = searchResults[indexPath.row] 
     }else{ 
      let wordKey = sectionTitles[indexPath.section] 
      if let items = cockpitDict[wordKey]{ 
       result = items[indexPath.row] 
      } 
     } 
     return result 
    } 

    // MARK: - Table view data source 

    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 
     return sectionTitles[section] 
    } 

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     //assume a single section after a search 
     return (searchController.active) ? 1 : sectionTitles.count 
    } 

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

     if searchController.active { 
      return searchResults.count 
     } else { 
      // Return the number of rows in the section. 
      let wordKey = sectionTitles[section] 
      if let items = cockpitDict[wordKey] { 
       return items.count 
      } 

      return 0 
     } 
    } 


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

     let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DictionaryTableViewCell 

     //let dictionary = (searchController.active) ? searchResults[indexPath.row]: dictionaryItems[indexPath.row] 
     if let dictionary = itemForIndexPath(indexPath){ 
      cell.wordLabel.text = dictionary.word 
      cell.definitionSmallLabel.text = dictionary.definition 
      cell.typeLabel.text = dictionary.type 
      cell.yearLabel.text = dictionary.year 
      cell.countryLabel.text = dictionary.country 


     }else{ 
      print("Cell error with path\(indexPath)") 
     } 
      return cell 
    } 

    override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? { 
     return sectionTitles 
    } 

    // Override to support conditional editing of the table view. 
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { 
     // Return false if you do not want the specified item to be editable. 
     if searchController.active{ 
      return false 
     }else{ 
      return true 
     } 
    } 

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
     if segue.identifier == "showDictionaryDetail" { 
      if let indexPath = tableView.indexPathForSelectedRow { 
       let destinationController = segue.destinationViewController as! DictionaryDetailViewController 
       if let dictionary = itemForIndexPath(indexPath){ 
        destinationController.dictionary = dictionary 
       }else{ 
        print("Segue error with path \(indexPath)") 
       } 
       searchController.active = false 
      } 
     } 
    } 

    func updateSearchResultsForSearchController(searchController: UISearchController) { 
      if let searchText = searchController.searchBar.text { 
       filterContentForSearchText(searchText) 
       tableView.reloadData() 
      } 
    } 

    func filterContentForSearchText(searchText: String) { 
     searchResults = dictionaryItems.filter({ (dictionary:Dictionary) -> Bool in 
      let wordMatch = dictionary.word!.rangeOfString(searchText, options: 
       NSStringCompareOptions.CaseInsensitiveSearch) 
      return wordMatch != nil 
     }) 
    }  
} 

//ScopeBar try: all lines below got many errors I can not figure out how to fix it :(

func filterContentForSearchText(searchText: String, scope: String = "All") { 
    dictionaryItems = cockpitDict.filter({(cockpitDict : Dictionary) -> Bool in 
     let categoryMatch = (scope == "All") || (cockpitDict.category == scope) 
     return categoryMatch && cockpitDict.name.lowercaseString.containsString(searchText.lowercaseString) 
    }) 
    tableView.reloadData() 
} 

extension DictionaryTableViewController:UISearchBarDelegate { 
    // MARK: - UISearchBar Delegate 
    func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { 
     filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope]) 
    } 
} 

extension DictionaryTableViewController: UISearchResultsUpdating { 
    // MARK: - UISearchResultsUpdating Delegate 
    func updateSearchResultsForSearchController(searchController: UISearchController) { 
     let searchBar = searchController.searchBar 
     let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex] 
     filterContentForSearchText(searchController.searchBar.text!, scope: scope) 
    } 
} 
+0

Quale versione di Swift stai usando? Anche 'var searchResults: [Dictionary] = []' non viene compilato per me. Forse il primo passo è aggiornare alla versione corrente di Swift. –

+0

@ Dave Batton la mia versione xcode è la 7.2.1 (7C1002) l'ultima versione disponibile. –

+0

@Jade di sicuro non capirai il motivo per cui il tuo codice non funziona, in quanto non viene nemmeno compilato. Correggi i tuoi errori del compilatore e poi vediamo cosa c'è di sbagliato nel tuo codice – EridB

risposta

3

ho passato tutto il codice fornito in github e risolto esso

Cambia la tua viewDidLoad a

override func viewDidLoad() { 
     super.viewDidLoad() 

     // Load menu items from database 
     if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext { 

      let fetchRequest = NSFetchRequest(entityName: "DictionaryEntity") 
      do { 
       dictionaryItems = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Dictionary] 
      } catch { 
       print("Failed to retrieve record") 
       print(error) 
      } 
     } 

     searchController = UISearchController(searchResultsController: nil) 
     tableView.tableHeaderView = searchController.searchBar 
     searchController.searchResultsUpdater = self 
     searchController.dimsBackgroundDuringPresentation = false 
     searchController.searchBar.placeholder = "Search ..." 

// you were setting before initialization 
     searchController.searchBar.scopeButtonTitles = ["All", "type", "year", "country"] 

     navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: 
      .Plain, target: nil, action: nil) 

     // Enable self sizing cells 
     tableView.estimatedRowHeight = 100.0 
     tableView.rowHeight = UITableViewAutomaticDimension 


     createCockpitDict() 
    } 

e per ultimo scopebar filtraggio

func filterContentForSearchText(var searchText: String, scope: NSInteger) { 


searchText = searchText.lowercaseString; 

func checkString(strData: String, strSearchData: String)-> Bool{ 
    return strData.rangeOfString(strSearchData, options: 
     NSStringCompareOptions.CaseInsensitiveSearch) != nil 
} 

searchResults = dictionaryItems.filter({ (dictionary:Dictionary) -> Bool in 

    switch scope { 
    case 0: 
     return (checkString(dictionary.word!, strSearchData: searchText) || checkString(dictionary.type!, strSearchData: searchText) || checkString(dictionary.country!, strSearchData: searchText) || checkString(dictionary.year!, strSearchData: searchText)) 
    case 1: 
     return checkString(dictionary.type!, strSearchData: searchText) 
    case 2: 
     return checkString(dictionary.year!, strSearchData: searchText) 
    case 3: 
     return checkString(dictionary.country!, strSearchData: searchText) 
    default: 
     return true; 
    } 

}) 

tableView.reloadData() 

} 


// MARK: - UISearchBar Delegate 
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { 
     filterContentForSearchText(searchBar.text!, scope: searchBar.selectedScopeButtonIndex) 
} 



// MARK: - UISearchResultsUpdating Delegate - comment older method so duplicate method error will be vanished 
func updateSearchResultsForSearchController(searchController: UISearchController) { 
    let searchBar = searchController.searchBar 
    filterContentForSearchText(searchController.searchBar.text!, scope: searchBar.selectedScopeButtonIndex) 
} 
+0

Ciao grazie per la correzione, sto ancora ricevendo tre errori nel filtro della barra dell'ambito: searchResults = dictionaryItems.filter ({..... = uso dell'identificatore non risolto 'searchResults' & 'dictionaryItems' + in linea: tableView.reloadData() = uso dell'identificatore non risolto "tableView" .Grazie per il tuo tempo :) –

+2

Hey devi aggiungere questa parentesi fuori classe, controllala – techloverr

+2

Perché la metti al di fuori della classe che ho controllato e ha eseguito il tuo codice – techloverr

3

Ci sono alcuni problemi con questo codice. Per i principianti, come altri hanno sottolineato, var searchResults:[Dictionary] = [] non è una sintassi valida. A Dictionary in Swift richiede una specifica di tipo, ad esempio Dictionary<String: AnyObject>. Sto indovinando in base al resto del codice che hai nominato un'entità personalizzata denominata Dictionary, che potrebbe causare la confusione.

Il prossimo numero che vedo è che sulle righe 8 e 10, è necessario inizializzare l'array, utilizzando (), ad esempio var searchResults:[Dictionary] = [](). (Di nuovo, questo sta assumendo a risolvere il problema di dichiarare il tipo di Dictionary correttamente.)

Un altro problema è la tua filter dichiarazione sulla linea 192:

dictionaryItems = cockpitDict.filter({(cockpitDict : Dictionary) -> Bool in 
    let categoryMatch = (scope == "All") || (cockpitDict.category == scope) 
    return categoryMatch && cockpitDict.name.lowercaseString.containsString(searchText.lowercaseString) 
}) 

Diamo uno sguardo alla definizione di cockpitDict on line 12:

private var cockpitDict = [String: [Dictionary]]() 

Poiché questo è un Array con una chiave e un valore StringArray<Dictionary>, avete sia un key e value da catturare nella chiusura. La dichiarazione del filtro deve essere diverso, qualcosa di simile (ancora una volta, ho fatto alcune ipotesi sulla definizione del tipo personalizzato Dictionary):

dictionaryItems = cockpitDict.filter({(key, value) -> Bool in 
    let categoryMatch = (scope == "All") || (value.category == scope) 
    return categoryMatch && value.name.lowercaseString.containsString(searchText.lowercaseString) 
})