【问题标题】:Adding Scope Bar in swift快速添加范围栏
【发布时间】:2016-06-12 16:32:37
【问题描述】:

该应用在带有搜索栏的表格视图中显示它正在使用的汽车零件列表(汽车零件、类型、年份、国家/地区)。

现在我决定添加一个范围栏来过滤结果,我确定我搞砸了代码。添加scopeBar的行中有很多错误。这是最后 20 行,在注释 //ScopeBar try 之后,除了最后几行之外,我在 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)
    }
}

【问题讨论】:

  • 您使用的是什么版本的 Swift?甚至 var searchResults:[Dictionary] = [] 也无法为我编译。也许第一步是更新到当前版本的 Swift。
  • @Dave Batton 我的 xcode 版本是 7.2.1(7C1002) 最后一个可用版本。
  • @Jade 你肯定不会明白你的代码不能工作的原因,因为它甚至没有被编译。修复你的编译器错误,然后我们可以看到你的代码有什么问题
  • 我不认为拥有最新版本的 Xcode 与使用最新版本的 Swift 是一样的。您是否看到编译器警告告诉您升级到最新版本的 Swift 或更新您的项目设置?
  • 否,编译器不要求更新。 :(

标签: ios swift uisearchbar


【解决方案1】:

我浏览了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)
}

【讨论】:

  • 您好,感谢您的更正,我在范围栏过滤中仍然遇到三个错误:searchResults = dictionaryItems.filter({..... = 使用未解析的标识符 'searchResults' & 'dictionaryItems' + 在行中:tableView.reloadData() = 使用未解析的标识符“tableView”。感谢您的时间:)
  • 嘿,你一定是在课堂括号外添加了这个,检查一下
  • 因为你把它放在我检查并运行你的代码的类之外
  • 看你的问题,你已经添加了这个方法超出了范围
  • 我刚开始聊天也许更好:) chat.stackoverflow.com/rooms/106113/scopebar
【解决方案2】:

此代码存在一些问题。对于初学者,正如其他人指出的那样,var searchResults:[Dictionary] = [] 不是有效的语法。 Swift 中的Dictionary 需要类型说明,例如Dictionary&lt;String: AnyObject&gt;。我根据你的其余代码猜测你已经命名了一个名为 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]]()

因为这是一个带有String 键和Array&lt;Dictionary&gt; 值的Array,所以您可以在闭包中同时捕获keyvalue。过滤器语句需要不同,像这样(同样,我对自定义Dictionary 类型的定义做了一些假设):

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-11
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 2010-11-14
    相关资源
    最近更新 更多