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