2015-08-25 1 views
0

Я новичок в Swift, поэтому будьте нежны.Проблемы с населением UISearchBarController Results TableView

В настоящее время я использую бета-версию Xcode 7.

У меня есть TableViewController, вложенный в NavigationController. В TableView я реализовал UISearchBar и UISearchDisplayController, аналогично шагам here. Практически все работает так, как ожидалось, за исключением случаев, когда я набираю критерии поиска, представление таблицы результатов для UISearchDisplayController не заполняется. Когда я ударил Отмена при поиске, результаты были заполнены в начальном виде таблицы.

Учебник, с которым я связан, предварительно заполняет список элементов, и панель поиска фильтрует эти элементы. Мой подход отличается от того, что я заполняю поиск из внешнего API.

Мой вопрос два раза:

а) как я правильно заполнить 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 каждый раз, когда текст изменяется ,

Надеюсь, я правильно это объяснил. Пожалуйста, не стесняйтесь редактировать вопрос, если я не понял или пропустил что-то.

ответ

0

Итак, я получил функциональность, которую хотел, и в конечном итоге ответил на мой вопрос о том, какой был правильный подход. Оказывается, я пытался подогнать квадратный колышек в круглое отверстие.

Что я в итоге сделал, снимая 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, пока пользователь не было сделано, печатая), и я также был в состоянии удалить код, который был постороннее. Надеюсь, это поможет кому-то в будущем.