该应用程序显示了在带有搜索栏的tableview中工作的汽车零件(汽车零件,类型,年份,国家)的列表。
现在我决定添加一个范围栏来过滤结果,我确信我搞砸了代码。添加scopeBar的行中有许多错误。在评论//ScopeBar try
之后的最后20行,除了最后一行之外,我在viewDidLoad()
中添加了一个代码来显示我想要的标题。
我做错了什么?任何帮助都非常受欢迎,我试图解决这个问题2天已经没有运气了。
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 :(得分:4)
我浏览了github中提供的完整代码并解决了它
将viewDidLoad更改为
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()
}
和最后一个范围栏过滤
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)
}
答案 1 :(得分:3)
此代码存在一些问题。对于初学者,正如其他人所指出的那样,var searchResults:[Dictionary] = []
不是有效的语法。 Swift中的Dictionary
需要类型规范,例如Dictionary<String: AnyObject>
。我猜测你的代码的其余部分已经命名为一个名为Dictionary
的自定义实体,这可能会引起混淆。
我看到的下一个问题是,在第8行和第10行,您需要使用()
初始化数组,即var searchResults:[Dictionary] = []()
。 (同样,这是假设您正确解决了正确声明Dictionary
类型的问题。)
另一个问题是第192行的filter
声明:
dictionaryItems = cockpitDict.filter({( cockpitDict : Dictionary) -> Bool in
let categoryMatch = (scope == "All") || (cockpitDict.category == scope)
return categoryMatch && cockpitDict.name.lowercaseString.containsString(searchText.lowercaseString)
})
让我们看一下第12行cockpitDict
的定义:
private var cockpitDict = [String: [Dictionary]]()
由于这是一个Array
,其String
键和Array<Dictionary>
值,因此您需要在闭包中捕获key
和value
。 filter语句需要不同,类似这样(再次,我对自定义Dictionary
类型的定义做了一些假设):
dictionaryItems = cockpitDict.filter({(key, value) -> Bool in
let categoryMatch = (scope == "All") || (value.category == scope)
return categoryMatch && value.name.lowercaseString.containsString(searchText.lowercaseString)
})