Swift/iOS 8: search bar raising fatal error: unexpectedly found nil while unwrapping an Optional value
Swift/iOS 8: search bar raising fatal error: unexpectedly found nil while unwrapping an Optional value
按照 this 教程,我刚刚向我的 Table 视图控制器添加了一个 "Search Bar and Search Display Controller"。
正如您从以下屏幕截图中看到的,table 和搜索栏已正确加载:
通过使用 "Cell" 作为小区重用标识符。
不管怎样,有两个问题:
1) 当点击搜索栏时,即使它仍然接受要搜索的文本,它也会简单地消失在导航栏下方
2) 一旦我开始在搜索栏中输入内容(即使它是 "hidden"),就会引发标题中提到的异常。
这是我的代码,其中带有 /***/ 的行是引发异常的地方:
import UIKit
class AllTasksViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
var allTasks = [Task]()
var taskService = TaskService()
var organizedTasks = TaskMenuItems()
var filteredTasks = [Task]()
override func viewWillAppear(animated: Bool) {
self.tabBarController?.navigationItem.setHidesBackButton(true, animated: true)
self.tabBarController?.navigationItem.rightBarButtonItem = self.editButtonItem()
if (LoggedUser.isLogged) {
self.navigationItem.setHidesBackButton(false, animated: true)
self.taskService.requestAllTasks {
(response) in
self.allTasks = self.taskService.loadTasks(response) as! [Task]
self.organizedTasks.organize(self.allTasks)
/*println(self.organizedTasks.items["Aperti"]?.count)
println(self.organizedTasks.items["Chiusi"]?.count)
println(self.organizedTasks.items["Scaduti"]?.count)
println(self.organizedTasks.items["Sospesi"]?.count)*/
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/* Number of sections */
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.organizedTasks.sections.count
}
/* Number of rows for each section */
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredTasks.count
}
switch section {
case 0:
return self.organizedTasks.items["Aperti"]!.count
case 1:
return self.organizedTasks.items["Chiusi"]!.count
case 2:
return self.organizedTasks.items["Scaduti"]!.count
case 3:
return self.organizedTasks.items["Sospesi"]!.count
default:
return -1
}
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
l?
var selectedStatus:String
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell /***/
var task:Task
if tableView == self.searchDisplayController!.searchResultsTableView {
task = filteredTasks[indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
switch indexPath.section {
case 0:
/*let cell = tableView.dequeueReusableCellWithIdentifier("OpenTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Aperti"
break
case 1:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ClosedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Chiusi"
break
case 2:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ExpiredTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Scaduti"
break
case 3:
/*let cell = tableView.dequeueReusableCellWithIdentifier("SuspendedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Sospesi"
break
default:
/*let cell = tableView.dequeueReusableCellWithIdentifier("",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = ""
break
}
task = self.organizedTasks.items[selectedStatus]![indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch (section) {
case 0:
let count = self.organizedTasks.items["Aperti"]!.count
return "Aperti (\(count))"
case 1:
let count = self.organizedTasks.items["Chiusi"]!.count
return "Chiusi (\(count))"
case 2:
let count = self.organizedTasks.items["Scaduti"]!.count
return "Scaduti (\(count))"
case 3:
let count = self.organizedTasks.items["Sospesi"]!.count
return "Sospesi (\(count))"
default:
return ""
}
}
func filterContentForSearchText(searchText: String, scope:String="All") {
// Filter the array using the filter method
self.filteredTasks = self.allTasks.filter({( task: Task) -> Bool in
let categoryMatch = (scope == "All") || (task.priorita == scope)
let stringMatch = task.titolo.rangeOfString(searchText)
return categoryMatch && (stringMatch != nil)
})
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearchText(searchString)
return true
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchScope searchOption: Int) -> Bool {
self.filterContentForSearchText(self.searchDisplayController!.searchBar.text)
return true
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
}
我不知道为什么会出现这两件事。它似乎无法使用 "Cell" 标识符创建另一个单元格,但这很奇怪,因为当加载 table 时(不使用搜索栏)一切正常,因此标识符 Cell 已注册。
请问,你能帮忙吗?
在您配置搜索显示控制器的地方或 viewDidLoad
中尝试以下代码:
self.searchDisplayController.searchResultsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
另外,使用tableView.
dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
值得一提的是,UISearchDisplayController
在iOS8中已弃用,请改用UISearchController
。
按照 this 教程,我刚刚向我的 Table 视图控制器添加了一个 "Search Bar and Search Display Controller"。 正如您从以下屏幕截图中看到的,table 和搜索栏已正确加载:
通过使用 "Cell" 作为小区重用标识符。 不管怎样,有两个问题:
1) 当点击搜索栏时,即使它仍然接受要搜索的文本,它也会简单地消失在导航栏下方
2) 一旦我开始在搜索栏中输入内容(即使它是 "hidden"),就会引发标题中提到的异常。
这是我的代码,其中带有 /***/ 的行是引发异常的地方:
import UIKit
class AllTasksViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
var allTasks = [Task]()
var taskService = TaskService()
var organizedTasks = TaskMenuItems()
var filteredTasks = [Task]()
override func viewWillAppear(animated: Bool) {
self.tabBarController?.navigationItem.setHidesBackButton(true, animated: true)
self.tabBarController?.navigationItem.rightBarButtonItem = self.editButtonItem()
if (LoggedUser.isLogged) {
self.navigationItem.setHidesBackButton(false, animated: true)
self.taskService.requestAllTasks {
(response) in
self.allTasks = self.taskService.loadTasks(response) as! [Task]
self.organizedTasks.organize(self.allTasks)
/*println(self.organizedTasks.items["Aperti"]?.count)
println(self.organizedTasks.items["Chiusi"]?.count)
println(self.organizedTasks.items["Scaduti"]?.count)
println(self.organizedTasks.items["Sospesi"]?.count)*/
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/* Number of sections */
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.organizedTasks.sections.count
}
/* Number of rows for each section */
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredTasks.count
}
switch section {
case 0:
return self.organizedTasks.items["Aperti"]!.count
case 1:
return self.organizedTasks.items["Chiusi"]!.count
case 2:
return self.organizedTasks.items["Scaduti"]!.count
case 3:
return self.organizedTasks.items["Sospesi"]!.count
default:
return -1
}
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
l?
var selectedStatus:String
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell /***/
var task:Task
if tableView == self.searchDisplayController!.searchResultsTableView {
task = filteredTasks[indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
switch indexPath.section {
case 0:
/*let cell = tableView.dequeueReusableCellWithIdentifier("OpenTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Aperti"
break
case 1:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ClosedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Chiusi"
break
case 2:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ExpiredTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Scaduti"
break
case 3:
/*let cell = tableView.dequeueReusableCellWithIdentifier("SuspendedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Sospesi"
break
default:
/*let cell = tableView.dequeueReusableCellWithIdentifier("",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = ""
break
}
task = self.organizedTasks.items[selectedStatus]![indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch (section) {
case 0:
let count = self.organizedTasks.items["Aperti"]!.count
return "Aperti (\(count))"
case 1:
let count = self.organizedTasks.items["Chiusi"]!.count
return "Chiusi (\(count))"
case 2:
let count = self.organizedTasks.items["Scaduti"]!.count
return "Scaduti (\(count))"
case 3:
let count = self.organizedTasks.items["Sospesi"]!.count
return "Sospesi (\(count))"
default:
return ""
}
}
func filterContentForSearchText(searchText: String, scope:String="All") {
// Filter the array using the filter method
self.filteredTasks = self.allTasks.filter({( task: Task) -> Bool in
let categoryMatch = (scope == "All") || (task.priorita == scope)
let stringMatch = task.titolo.rangeOfString(searchText)
return categoryMatch && (stringMatch != nil)
})
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearchText(searchString)
return true
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchScope searchOption: Int) -> Bool {
self.filterContentForSearchText(self.searchDisplayController!.searchBar.text)
return true
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
}
我不知道为什么会出现这两件事。它似乎无法使用 "Cell" 标识符创建另一个单元格,但这很奇怪,因为当加载 table 时(不使用搜索栏)一切正常,因此标识符 Cell 已注册。 请问,你能帮忙吗?
在您配置搜索显示控制器的地方或 viewDidLoad
中尝试以下代码:
self.searchDisplayController.searchResultsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
另外,使用tableView.
dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
值得一提的是,UISearchDisplayController
在iOS8中已弃用,请改用UISearchController
。