无法填充 UISearchBarController 结果 TableView

Trouble Populating UISearchBarController Results TableView

我是Swift的新手,所以要温柔。

我目前正在使用 Xcode 7 Beta。

我有一个嵌套在 NavigationController 中的 TableViewController。在 TableView 中,我实现了一个 UISearchBarUISearchDisplayController,类似于步骤 here。几乎一切都按预期工作,除了当我键入我的搜索条件时,UISearchDisplayController 的结果 table 视图没有被填充。当我在搜索中点击 Cancel 时,结果已填充到初始 table 视图中。

我链接到的教程正在预填充项目列表,搜索栏正在过滤这些项目。我的方法不同,因为我从外部 API.

填充搜索

我的问题有两个:

a) 如何正确填充结果 TableView?

b) 这两个 TableView 似乎是多余的,我觉得第一个没有必要(可能是错误的)。实现此功能的正确方法是什么?理想情况下,我希望能够在导航项中放置一个 UISearchBar,以便它位于 UINavigationBar 中,但我很难找到这样做的资源。

import UIKit
import Alamofire
import SwiftyJSON
import Foundation

class DSTableViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {

  var songs: [Song] = []
  var timer: NSTimer = NSTimer()

  func getSongs(timer: NSTimer!) {

    let searchTerm = timer.userInfo as! String

    self.title = "Results for \(searchTerm)"

    // logic to switch service; need to eventually move this to an interface
    // or move this code inside a rest API, and then into an interface

    // URL encode the search term
    let searchTermEncoded = searchTerm.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())

    // create the url for the web request
    let uri: String = "https://api.spotify.com/v1/search?q=\(searchTermEncoded!)&type=artist,album,track"

    // call to Spotify API
    Alamofire
        .request(.GET, uri)
        .response { request, response, data, error in

            let json = JSON(data: data!)

            print(json["tracks"]["items"].count);
            print(json["tracks"]["items"])

            for var i = 0; i < json["tracks"]["items"].count; i++ {

                let data = json["tracks"]["items"][i]

                // return the object list
                let song = Song()

                song.title = data["name"].string!
                song.album = data["album"]["name"].string!
                song.artist = data["artists"][0]["name"].string!

                self.songs += [song]

            }

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

  }

  override func viewDidLoad() {
    super.viewDidLoad()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
  }

  func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String?) -> Bool {

    timer.invalidate()

    timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("getSongs:"), userInfo: searchString, repeats: false)

    return true

  }

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

  // MARK: - Table view data source

  override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
  }

  override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return songs.count
  }


  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("SongCell", forIndexPath: indexPath)

    let song = songs[indexPath.row]

    cell.textLabel?.text = song.title
    cell.detailTextLabel?.text = song.artist + " - " + song.album
    cell.imageView?.image = song.albumImage

    return cell
  }
}

当我打电话给

func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String?) -> Bool {

    self.getSongs(searchString)

    return true

  }

我能够正确填充视图,但我希望有延迟,这样我就不会在每次文本更改时都进行 API 调用。

希望我解释正确。如果我不清楚或遗漏了什么,请随时编辑问题。

所以我最终获得了我想要的功能,并最终回答了我关于正确方法是什么的问题。原来我是想把方钉塞进圆孔里。

我最终做的是完全删除 UISearchDisplayController,而只是创建一个 UISearchBar 并将其分配给我的 self.navigationItem.titleView。这删除了搜索控制器的一些内置功能,但也为我提供了一种更简洁的方式来做我需要做的事情,而不用担心愚蠢的解决方法。我的代码看起来大致像

class TableViewController: UISearchBarDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let searchBar: UISearchBar = UISearchBar()

        searchBar.placeholder = "Search"
        searchBar.delegate = self

        self.navigationItem.titleView = searchBar

        self.definesPresentationContext = true
    }


    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        timer.invalidate()

        timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "getResults:", userInfo: searchText, repeats: false)
    }

    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        searchBar.resignFirstResponder()
    }

}

这种方法让我获得了我正在寻找的功能(能够延迟对 API 的调用,直到用户完成输入),而且我还能够删除一些无关的代码。希望这对以后的人有所帮助。