UISearchBar textDidChange 来自 plist 的数据

UISearchBar textDidChange data from plist

我想搜索我的 plist 中的项目。 plist 由一系列字典组成。每个 key/value 代表 Strings/Ints,等等,但这并不重要。

正如您将在下面的 tableViewController class 中看到的,我目前已经输入了一个数组。我知道我需要从我的 plist 中创建一个 objects/items 数组,但我不知道如何在视图控制器中从 plist 中引用对象。

查看controller.swift 文件:

import UIKit

class TableViewController: UITableViewController, UISearchResultsUpdating {

var array = ["Example 1", "Example 2", "Example 3"]
var filteredArray = [String]()
var searchController = UISearchController()
var resultsController = UITableViewController()

override func viewDidLoad() {
    super.viewDidLoad()

    searchController = UISearchController(searchResultsController: resultsController)
    tableView.tableHeaderView = searchController.searchBar
    searchController.searchResultsUpdater = self

    resultsController.tableView.delegate = self
    resultsController.tableView.dataSource = self
}

//Added func to update search results
func updateSearchResults(for searchController: UISearchController) {
    filteredArray = array.filter({ (array:String) -> Bool in
        if array.contains(searchController.searchBar.text!) {
            return true
        } else {
            return false
        }
        })
    resultsController.tableView.reloadData()
}

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

extension TableViewController {

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if tableView == resultsController.tableView {
        return filteredArray.count
    } else {
    return array.count
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()

    if tableView == resultsController.tableView {
    cell.textLabel?.text = filteredArray[indexPath.row]
    } else {
        cell.textLabel?.text = array[indexPath.row]
    }
    return cell
}
}

我已经尝试通过在 plist 上的教程中创建一个对象 class 来解决这个问题。它使用周期性 table 元素的示例:

import UIKit

struct Element {
enum State: String {
    case Solid, Liquid, Gas
}

let atomicNumber: Int
let atomicWeight: Float
let discoveryYear: String
let group: Int
let name: String
let period: Int
let radioactive: Bool
let state: State
let symbol: String

// Position in the table
let horizPos: Int
let vertPos: Int
}

extension Element {
enum ErrorType: Error {
    case noPlistFile
    case cannotReadFile
}

/// Load all the elements from the plist file
static func loadFromPlist() throws -> [Element] {
    // First we need to find the plist
    guard let file = Bundle.main.path(forResource: "Element", ofType: "plist") else {
        throw ErrorType.noPlistFile
    }

    // Then we read it as an array of dict
    guard let array = NSArray(contentsOfFile: file) as? [[String: AnyObject]] else {
        throw ErrorType.cannotReadFile
    }

    // Initialize the array
    var elements: [Element] = []

    // For each dictionary
    for dict in array {
        // We implement the element
        let element = Element.from(dict: dict)
        // And add it to the array
        elements.append(element)
    }

    // Return all elements
    return elements
}

/// Create an element corresponding to the given dict
static func from(dict: [String: AnyObject]) -> Element {
    let atomicNumber = dict["atomicNumber"] as! Int
    let atomicWeight = Float(dict["atomicWeight"] as! String) ?? 0
    let discoveryYear = dict["discoveryYear"] as! String
    let group = dict["group"] as! Int
    let name = dict["name"] as! String
    let period = dict["period"] as! Int
    let radioactive = dict["radioactive"] as! String == "True"
    let state = State(rawValue: dict["state"] as! String)!
    let symbol = dict["symbol"] as! String
    let horizPos = dict["horizPos"] as! Int
    let vertPos = dict["vertPos"] as! Int

    return Element(atomicNumber: atomicNumber,
                     atomicWeight: atomicWeight,
                     discoveryYear: discoveryYear,
                     group: group,
                     name: name,
                     period: period,
                     radioactive: radioactive,
                     state: state,
                     symbol: symbol,
                     horizPos: horizPos,
                     vertPos: vertPos)
}
}

并且在 viewController class 中,而不是

var array = ["Example 1", "Example 2", "Example 3"]

我试过

的变体
var array = Element["name"]

var array = elements.name

但它们显然不起作用,因为对 plist 的引用在对象中 class。

如果有人知道如何使用 swift 3/xcode 8 解决此问题,我将不胜感激!!

我希望你的问题仍然相关。据我了解,您不能过滤数组,对吗?如果是这样,我建议您查看 this and this 教程。它们都代表了一些不同的加载过滤数组的方法,但这并不重要,它们都有效。

P.S。我不建议你制作一个特殊的 tableView 用于搜索,如果你想在以后自定义它,因为你以后必须以编程方式进行。 这样做会更有效率:

  If searchController.isActive {
    // do some stuff
} else { // another stuff }

但这只是我的意见。希望我的问题对您有所帮助 ;).

感谢 Oleg 提供的链接。他们真的很棒!!

与其说是我遇到的过滤问题,不如说是将我的 plist 中的对象解析到 tableview 中。我花了几天时间,但我找到了答案,以防其他人也遇到同样的问题。请记住,我对此相当陌生,因此这可能不是 best/perfect 的做法,但它确实有效。

在 viewDidLoad 中,我使用以下代码引用了 plist:

    let path = Bundle.main.path(forResource: "Elements", ofType: "plist")
    let dictArray = NSArray(contentsOfFile: path!)

我不确定相关性,但我很确定如果需要更新 plist,则需要下一点。 (也在 viewDidLoad 中)

    for elementItem in dictArray! {
        let newElement : Element = Element(state:((elementItem as AnyObject).object(forKey: "state")) as! String, 
atomicNumber:((elementItem as AnyObject).object(forKey: "atomicNumber")) as! Int,
atomicWeight:((elementItem as AnyObject).object(forKey: "atomicWeight")) as! Float,
discoveryYear:((elementItem as AnyObject).object(forKey: "discoveryYear")) as! String

等对于字典中的每个键,其顺序与问题中 Element 对象中的顺序相同。然后(也在 viewDidLoad 中):

        elementsArray.append(newElement)

然后就很简单了,在 cellForRow 中,我只需要创建一个新变量来引用对象,然后我就可以调用 each/any 相关的字典键。例如:

let element : Element

cell.textLabel!.text = element.name
cell.detailTextLabel?.text = element.symbol
return cell

就像我说的,我知道它并不完美,但它对我有用。我听说在 viewDidLoad 中放置太多信息不是最佳做法,因此其他人可能能够确认或提供更好的答案。