I'm making an app, which destination iOS is 7.0. So I use search display controller. When i try to search, i make an api request, and it's results are coming later, than search display controller updates table view. So it's empty, though i have results of search. I've tried something like
self.searchDisplayController?.searchResultsTableView.reloadData()
straight after reaching data from request, but it's not working.
Here is my logic:
func filterContextForSearchText(searchText: String) {
BooksWorker.searchForBooks(searchText) { foundBooks in
self.foundBooks = foundBooks
if BooksWorker.books != nil {
self.filteredBooks = BooksWorker.books.filter { book in
return (book.name?.lowercaseString.containsString(searchText.lowercaseString))!
}
}
self.searchDisplayController?.searchResultsTableView.reloadData()
}
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String?) -> Bool {
isSearch = true
filterContextForSearchText(searchString!)
return true
}
I update my tableView in such a way:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearch {
tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
return filteredBooks.count
} else {
if BooksWorker.books != nil {
tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
return (BooksWorker.books?.count)!
} else {
showEmptyTableView()
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
return 0
}
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if isSearch {
let cell = tableView.dequeueReusableCellWithIdentifier(AppData.CellIdentifiers.UndownloadedBookCell) as! UndownloadedBookCell
print("making cell")
cell.setBook(foundBooks[indexPath.row])
cell.delegate = self
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier(AppData.CellIdentifiers.BookCell) as! BookCell
cell.setBook(BooksWorker.books![indexPath.row])
return cell
}
}
Does anybody having an idea?
you should update tableView not searchDisplay self.tableView.reloadData()
Related
So, I have method loadData() which download datas from parse.com
And I should present all images show in table view.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ReusableCell", forIndexPath: indexPath) as! LeaguesTableViewCell
loadData { (success) in
if success {
cell.leagueImage.image = UIImage(data: self.leaguesImage[indexPath.row])
cell.leagueNameLabel.text = self.leagues[indexPath.row]["name"] as? String
} else {
cell.leagueNameLabel.text = "Wait"
}
}
return cell
}
Its didn't work. I call my function in viewDidLoad() but its not correct too, table view is empty.
Cuz my array is empty
My
The basic procedure for loading data into a UITableView is:
Load the data
Reload the table view
Return the number of sections in numberOfSectionsInTableView: method: In your case there is only 1 section.
Return the number of rows in tableView:numberOfRowsInSection:: In your case return the number of leagues if the data is loaded. If the data is not loaded then return 1 so that the table view has at least one row to display the "Wait" message.
Create and populate the cells from the data: Use leagues and leaguesImage.
Example:
private var loaded = false
override func viewDidLoad() {
super.viewDidLoad()
loaded = false
loadData() { success in
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.loaded = success
self.tableView.reloadData()
}
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection: Int) -> Int {
if loaded {
return leagues.count
}
else {
return 1
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ReusableCell", forIndexPath: indexPath) as! LeaguesTableViewCell
if loaded {
cell.leagueImage.image = UIImage(data: self.leaguesImage[indexPath.row])
cell.leagueNameLabel.text = self.leagues[indexPath.row]["name"] as? String
}
else {
cell.leagueNameLabel.text = "Wait"
}
return cell
}
Try to set delegate and datasource first. If you have separate datasource other than view controller, retain it otherwise you will not get any callback.
I'm trying to GET gists from Github and pop them in a table view,
here's the entire code, Gist is a class defined elsewhere:
var gists = [Gist]()
override func viewDidAppear(animated: Bool) {
loadGists()
}
func loadGists() {
GithubAPIManager.sharedInstance.fetchPublicGists() { result in
guard result.error == nil else {
print("Error 1")
return
}
if let fetchedGists = result.value {
self.gists = fetchedGists
}
self.tableView.reloadData()
//Error here.
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return gists.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
let gist = gists[indexPath.row]
cell.textLabel?.text = gist.description
cell.detailTextLabel?.text = gist.ownerLogin
return cell
}
So, the problem is I didn't add an outlet of the table view to the View Controller.swift.
Just dragged the table view to the .swift file to create it.
I'm attempting to use the result of one Rest call as an input for my TableView.
I've got an array named GamesList[String] that is synthesized in the viewDidLoad() function. This is the viewDidLoad() fuction:
override func viewDidLoad() {
super.viewDidLoad()
getState() { (json, error) -> Void in
if let er = error {
println("\(er)")
} else {
var json = JSON(json!);
print(json);
let count: Int = json["games"].array!.count
println("found \(count) challenges")
for index in 0...count-1{
println(index);
self.GamesList.append(json["games"][index]["game_guid"].string!);
}
}
}
}
The problem is that the functions for filling the TableView get executed before my GamesList array is filled up. These are the functions that fill the TableView:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return GamesList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Game", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = GamesList[indexPath.row]
cell.detailTextLabel?.text = GamesList[indexPath.row]
return cell
}
How do I force the tables to get filled up (refreshed) after my array has been filled?
use self.tableView.reloadData() after you append your values
getState() { (json, error) -> Void in
if let er = error {
println("\(er)")
} else {
var json = JSON(json!);
print(json);
let count: Int = json["games"].array!.count
println("found \(count) challenges")
for index in 0...count-1{
println(index);
self.GamesList.append(json["games"][index]["game_guid"].string!);
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
I've created a UISearchBar App using this tutorial. Everything works fine, the cells are configured correctly, and I am able to search by username.
Now I am trying to add a (checkmark ✔︎) to each cell, allowing me to (select ✔︎) multiple users in a list.
The functionality works fine, but when I search the list, (select ✔︎) a user, and return to the main tableview, the user DOES NOT remain selected and vice-versa.
How can I (checkmark ✔︎) multiple users and maintain that checkmark before or after I use the UISearchBar?
class InviteViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate {
var allFriends = [Friend]()
var filteredFriends = [Friend]()
override func viewDidLoad() {
super.viewDidLoad()
###Call to get all Friends
getFriends()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredFriends.count
} else {
return self.allFriends.count
}
}
var selectedFriendIndex:Int? = nil
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
var friend : Friend
if tableView == self.searchDisplayController!.searchResultsTableView {
friend = filteredFriends[indexPath.row]
} else {
friend = allFriends[indexPath.row]
}
###Configure the cell
cell.textLabel!.text = friend.username
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
if (indexPath.row == selectedFriendIndex) {
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.None
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
selectedFriendIndex = indexPath.row
let cell = tableView.cellForRowAtIndexPath(indexPath)
if let index = selectedFriendIndex {
if (cell?.accessoryType == .Checkmark) {
cell!.accessoryType = .None
} else {
cell!.accessoryType = .Checkmark
}
}
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
self.filteredFriends = self.allFriends.filter({( friend : Friend) -> Bool in
var usernameMatch = (scope == "All") || (friend.username == scope)
var stringMatch = friend.username.lowercaseString.rangeOfString(searchText.lowercaseString)
return usernameMatch && (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
}
func searchDisplayController(controller: UISearchDisplayController, willHideSearchResultsTableView tableView: UITableView) {
self.tableView.reloadData()
}
}
You need to keep track of what friends are selected in (an array in) your model.
You could add a Bool for each friend, indicating whether they are selected.
This will preserve the selection information when you search and return.
You will need to add a Bool variable to your object and set it to true or false.
contact.addToGroup = false
Swift 3 example:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
let contact = contacts[indexPath.row]
if (cell.accessoryType == .checkmark) {
cell.accessoryType = .none
contact.addToGroup = false
} else {
cell.accessoryType = .checkmark
contact.addToGroup = true
}
}
tableView.deselectRow(at: indexPath, animated: true)
}
im doing a simple project in Xcode 6 and i want to add search bar in tableviewcontroller but something is not working for me. Im doing it by this tutorial
http://www.raywenderlich.com/76519/add-table-view-search-swift
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredProgramy.count
} else {
return self.programy.count
}
}
here im getting error "fatal error: unexpectedly found nil while unwrapping an Optional value". idk why. whole code is here
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredProgramy.count
} else {
return self.programy.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
var program : Program
if tableView == self.searchDisplayController!.searchResultsTableView {
program = filteredProgramy[indexPath.row]
} else {
program = programy[indexPath.row]
}
func filterContentForSearchText(searchText: String) {
// Filter the array using the filter method
var scope = String()
self.filteredProgramy = self.programy.filter({( program: Program) -> Bool in
let categoryMatch = (scope == "All") || (program.category == scope)
let stringMatch = program.name.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
}
}
self.searchDisplayController is nil.
I just downloaded the tutorial's sample code (which you should do as well) and I see that the author has a "Search Display Controller" in their nib file. Check your nib file and be sure that the Candy Search controller is hooked up properly.
It's supposed to look like this:
To get to that image right click on the Search Display Controller object in the .xib file. Notice in my image that "Referencing Outlets" has a connection between searchDisplayController and CandySearch. That's what you are missing.
To create the connection ctrl drag from the CandySearch controller to the `Search Display Controller" when you let go of the mouse you will see:
Click searchDisplayController and you should be good to go.
Lastly, you should read up on how optionals work in Swift to help you understand issues like this in the future:
https://developer.apple.com/librarY/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_456
I had a similar issue and found the following to work. The 'cell' variable in your code is nil because while you have set the number of rows, the actual cell object has not yet been created (line cell = UITableView(.. below)
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell
var player : Player
if self.searchDisplayController!.active {
var searchCell: AnyObject? = self.tableView.dequeueReusableCellWithIdentifier("Cell")
if searchCell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
} else {
cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell
}
player = self.filteredPlayers[indexPath.row]
} else {
cell = self.tableView.dequeueReusableCellWithIdentifier(TableCellNamesEnum.PLAYER_DETAIL_CELL.rawValue, forIndexPath: indexPath) as UITableViewCell
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
player = self.selectedPlayers[indexPath.row]
}
cell.textLabel!.text = "\(player.firstName) \(player.lastName)"
return cell
}