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 中放置太多信息不是最佳做法,因此其他人可能能够确认或提供更好的答案。
我想搜索我的 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 中放置太多信息不是最佳做法,因此其他人可能能够确认或提供更好的答案。