2015-10-13 52 views
4

我有一個UISearchController配置爲搜索非常大的數據數組。因此,當我在搜索欄中輸入內容時,實際輸入我的搜索需要很長時間。它執行與搜索字段中每個字符條目的搜索比較,這是非常緩慢的。UISearchController只在搜索按鈕點擊更新

我想知道如何解決這個問題。我的想法是:

  1. 只有在用戶完成後輸入和點擊搜索按鈕
  2. 執行在後臺線程搜索,釋放了鍵盤輸入

主線程執行搜索我想使用方法1 但我似乎無法弄清楚如何用新的UISearchController做到這一點。

下面是我的相關項目代碼:

class AirportSearchTBVC: UITableViewController, UISearchResultsUpdating{ 
var airportData = [Dictionary<String, String>]() 
var filteredData = [Dictionary<String, String>]() 
var searchController = UISearchController() 
override func viewDidLoad() { 
    super.viewDidLoad() 


    searchController = UISearchController(searchResultsController: nil) 
    searchController.searchResultsUpdater = self 

    searchController.dimsBackgroundDuringPresentation = false 

    searchController.searchBar.sizeToFit() 
    tableView.tableHeaderView = searchController.searchBar 

    definesPresentationContext = true 


    searchController.hidesNavigationBarDuringPresentation = false 

    self.tableView.reloadData() 
} 

func updateSearchResultsForSearchController(searchController: UISearchController) { 

    filteredData = [] 

    let searchPredicate = NSPredicate(format: "SELF CONTAINS[cd] %@", searchController.searchBar.text!) 
    let array = (airportData as NSArray).filteredArrayUsingPredicate(searchPredicate) 

    filteredData = array as! [Dictionary<String, String>] 

    self.tableView.reloadData() 

} 

獎金問題 如果我搜索一個字符串,它不會出現要返回任何結果,如果字符串不完全匹配。例如:「orida」沒有找到「Florida」。我的搜索謂詞是不是應該使用CONTAINS來找到它?

更新 這段代碼幾乎可以工作,但它基本上在後臺線程上拋出了一堆東西,然後突然通過它。鍵盤現在是熱鬧,但似乎如果我就很快改變的事情在文本框中,同時駁回和重新進入搜索欄崩潰......

func updateSearchResultsForSearchController(searchController: UISearchController) { 
    appDel.backgroundThread(background: { 
     self.filteredData.removeAll(keepCapacity: false) 

     let searchPredicate = NSPredicate(format: "SELF CONTAINS[cd] %@", searchController.searchBar.text!) 
     let array = (self.airportData as NSArray).filteredArrayUsingPredicate(searchPredicate) 

     self.filteredData = array as! [Dictionary<String, String>] 
     }, 
     completion: { 

      dispatch_async(dispatch_get_main_queue()) { 
        self.tableView.reloadData() 
      } 

    }); 






} 

更新2 打了一下後,有了它,我可以通過等待searchBar.text長度> = 3個字符以及確保字符數在updateSearchResultsForSearchController的1秒內沒有改變的方式使它正常工作:被調用。這些組合以及集成搜索按鈕執行命令應該可以解決我的問題。

func updateSearchResultsForSearchController(searchController: UISearchController) { 
    let startCount = searchController.searchBar.text!.length 
    delay(1) { 
    if searchController.searchBar.text!.length >= 3 && searchController.searchBar.text!.length == startCount{ 
     self.view.addSubview(self.progressHud) 
     self.appDel.backgroundThread(background: { 
      self.filteredData.removeAll(keepCapacity: false) 

      let searchPredicate = NSPredicate(format: "SELF CONTAINS[cd] %@", searchController.searchBar.text!) 
      let array = (self.airportData as NSArray).filteredArrayUsingPredicate(searchPredicate) 

      self.filteredData = array as! [Dictionary<String, String>] 
      }, 
      completion: { 
       dispatch_async(dispatch_get_main_queue()) { 
        self.tableView.reloadData() 
        self.progressHud.removeFromSuperview() 
       } 



     }); 
    } 
    } 





} 
    func delay(delay:Double, closure:()->()) { 
     dispatch_after(
      dispatch_time(
       DISPATCH_TIME_NOW, 
       Int64(delay * Double(NSEC_PER_SEC)) 
      ), 
      dispatch_get_main_queue(), closure) 
    } 

回答

6

您可以使用委託方法searchBarSearchButtonPressed:按下搜索按鈕時,監控。在執行此委託方法時設置一個標誌,然後在您的searchBarTextDidChange:方法中您可以檢查此標誌以查看是否應執行搜索。當然,這隻會在用戶按下搜索之後進行搜索,並且大多數人希望在鍵入時看到某些事情發生。

+0

有推薦的另一種策略嗎?考慮到人們期望看到不同的東西? – Charlie

+0

那麼你可以把你的整個'searchBarTextDidChange:'執行放在GCD的後臺線程中,然後在更新'tableView'之前,你可以跳回主線程以確保UI更新快。 – pbush25

+0

我已經更新了我的問題,嘗試執行您推薦的代碼,但實質上是因爲它在後臺線程中放入了很多請求,然後通過每個請求「突然跳出」......我真的很感謝您的幫助這裏:) – Charlie

4

如果你想只執行搜索時,用戶點擊「搜索」按鈕 - 這似乎都合情合理的放大和較慢的訪問數據集,你可以做這樣的:

class AirportSearchTBVC: UITableViewController, UISearchResultsUpdating{ 
var airportData = [Dictionary<String, String>]() 
var filteredData = [Dictionary<String, String>]() 
var searchController = UISearchController() 
override func viewDidLoad() { 
    super.viewDidLoad() 


    searchController = UISearchController(searchResultsController: nil) 
    searchController.searchResultsUpdater = self 
    searchController.searchBar.delegate = self 

    searchController.dimsBackgroundDuringPresentation = false 

    searchController.searchBar.sizeToFit() 
    tableView.tableHeaderView = searchController.searchBar 

    definesPresentationContext = true 


    searchController.hidesNavigationBarDuringPresentation = false 

    self.tableView.reloadData() 
} 

func searchBarSearchButtonClicked(searchBar: UISearchBar) { 
    filteredData = [] 

    let searchPredicate = NSPredicate(format: "SELF CONTAINS[cd] %@", searchController.searchBar.text!) 
    let array = (airportData as NSArray).filteredArrayUsingPredicate(searchPredicate) 

    filteredData = array as! [Dictionary<String, String>] 

    self.tableView.reloadData() 

} 
func updateSearchResultsForSearchController(searchController: UISearchController) { 

} 

關鍵區別在於設置searchController.searchBar.delegate = self,並將search代碼放入searchBarSearchButtonClicked函數中,而不是updateSearchResultsForSearchController - 現在應該什麼都不做。 我對任何錯誤表示歉意,我使用Xcode v7.0.1 Objective-C測試了這段代碼,然後調換了這些更改。

+0

欣賞你在這個答案中的努力,但我確實希望在更新後或在搜索按鈕按下時執行搜索。這可以很容易地幫助別人有類似的問題。謝謝! – Charlie