Implementing a search bar? - cocoa-touch

I have a project with a tableView created on the storyboard. It's pretty simple and I was following a tutorial to do it, my view controller looks like this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.textLabel.text = restaurantDisplayNames[indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES
];
}
So when you tap on a cell it puts a check mark next to it. Now I want people to be able to search for things. Problem is, Apple changed the search bar for iOS 8 and supposedly made it simpler but I can't find any tutorials on the UISearchController which replaced the depricated method.
So I dragged and dropped a Search Bar and Search Display Controller into my view controller and added the UISearchControllerDelegate, UISearchResultsUpdating> protocol declarations, but I get a crash:
'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
Whenever I tap on the search bar.
I also have the method
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{
}
But it is empty because I don't know what to put in there. Supposedly it is very easy and only requires a few lines of code to get it up and running, but the one tutorial I found here: http://www.stuartbreckenridge.com/blog/examining-the-new-uisearchcontroller-api now only is in swift but doesn't explain what goes in that method.

I figured it out. Man, some of these things are so ridiculously simple yet you have to dig deep to find answers. You'd think Apple could put some tips in XCode about these things, little warnings or something, but here's how I fixed it:
Apparently you need to add
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
In the cellForRowAtIndexPath: method so it looks like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = restaurantDisplayNames[indexPath.row];
return cell;
}
So it generates the cell if it doesn't exist. Not sure why, but oh well ...

Related

Search Bar in UITableView doesn't display text in Cell label

Here's where the magic isn't happening:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"songCell";
songViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
long row = indexPath.row;
if (cell == nil) {
cell = [[songViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.songLabel.text = _searchResults[row];
} else {
cell.songLabel.text = _songListArray[row];
}
return cell;
}
I know the _searchResults array is populated with the correct search results and I've edited the numberOfRowsPerSection appropriately. The filter is working correctly, but it won't display the _searchResults[row] text while typing into the search bar. If I don't use the bar, the cells are populated correctly with _songListArray[row].
Something is going wrong in:
if (cell == nil) {
cell = [[songViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
If I don't include the if expression, I get an error. How should I initialize the prototype cell while the search bar is in use? All I get is empty labels, but I know the search is working because if there are no filtered results in the array the table says "No Results" in the middle. Why isn't my songLabel.text updating?? It won't even display text when I set the label to #"HELLO??" instead of the array[row].
You need to have the searchResultsTableView dequeue a cell, not just your main table view. The cellForRowAtIndexPath method should look something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.tableView) {
RDTriangleCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
return cell;
}else{
UITableViewCell *cell = [self.searchDisplayController.searchResultsTableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
//RDCell *cell = [self.searchDisplayController.searchResultsTableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
cell.textLabel.text = self.filteredData[indexPath.row];
return cell;
}
}
In viewDidLoad, you should register the class if you use the code I show above for a standard UITableViewCell.
[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"SearchCell"];
If you use a custom cell for the search results table, then you should use something like the line I have commented out, and register the nib for that custom cell.

UITableViewCell didSelectRowAtIndexPath. Deselect the "not selected" cells when I select a new one

The title says it, and I think it's pretty much a no-brainer but I can't find the answer.
I think the code describes what I try to do.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Selected Row");
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
static NSString *CellIdentifier = #"accountCell";
UITableViewCell *allCells = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
allCells.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
So - first should all cells have no checkmarks, then I wanna add a checkmark to the selected one.
Every time the didSelectRowAtIndexPath method is called, go through a for loop that resets all the cells to their original accessory type. Then update the cell with the selected index path with a check mark like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for (UITableViewCell *cell in[self.tableView visibleCells]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
See here for a possible solution. You don't need to iterate over all cells

Xcode - Getting a cell to display new text after a touch event which makes it expand

I'm trying to have a dynamic table which expands on click to reveal some other content. I've got to the point where the table is populated with information from an NSMutableArray. I can also press each cell and it expands to double the size. Now, the next step, which is proving to be somewhat troublesome is to get it to display new/alternative text when they click on the cell. First of all, here's my setup method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
NSString *cellValue = [cellContent objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
return cell;
}
and after this, I have the method where the cell expands on press:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// If our cell is selected, return double height
if([self cellIsSelected:indexPath]) {
return kCellHeight * 2.0;
[cellContent replaceObjectAtIndex:[self cellIsSelected:indexPath] withObject:#"NEW STUFF HERE"];
}
I must be going about this in the wrong way as nothing changes when I touch the cell. How do I get it to display new/alternative text on touch? Any help would be super, I think it's likely to be something quite easy, but I can't see it at the moment.
Thanks!
Your second method is only triggered when the cell is built or rebuilt. You need to explicitly ask it to refresh itself in the following method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
And then within that method, you can call
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
and now your redraw methods will be triggered, so you can handle whatever you want there.

Why is my UITableView not being updated?

Why does my UITableView not update? Here is how I am attempting to update it.
- (void)viewWillAppear:(BOOL)animated
{
NSArray* arrValues = [self.defaults objectForKey:#"values"];
[self.tableScores insertRowsAtIndexPaths:arrValues withRowAnimation:UITableViewRowAnimationNone];
}
arrValues is now an array of NSNumbers. I am sure that it is not empty.
Call [tableScores reloadData]; in - (void)viewWillAppear:(BOOL)animated
Update 1
Also, you need to define arrValues in your header. Each time the viewWillAppear, you are creating a new instance, but you won't be able to use it throughout the rest of your controller. This is the main reason you aren't seeing anything besides at your breakpoint.
Update 2
According to your comment below, you have not implemented cellForRowAtIndexPath: which is how the cell is created. Below is an example, but you may want to search around the net for example projects because this UITableView's 101. There is still a lot more you need to learn when it comes to arrays and tableViews.
Example cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"FriendCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [arrValues objectAtIndex:indexPath.row];
return cell;
}

Why are checkmarks not being displayed when UITableView.allowsMultipleSelection is enabled?

I have a UITableView in an iOS5.1 app where I set
self.tableView.allowsMultipleSelection=YES;
The Apple documentation states "When the value of this property is YES, a check mark is placed next to each row that is tapped. Tapping the row again removes the check mark.".
I am able to select multiple rows as the background is set to Blue. However, no checkmarks are displayed. Does the checkmark need to be set as shown below in didSelectRowAtIndexPath because I am using custom UITableViewCells?
cell.accessoryType = UITableViewCellAccessoryCheckmark;
I do the checkmarks manually in my uitableviewcell subclasses. You are going to have to do the UITableViewCellAccessoryCheckmark manually in didSelectRowAtIndexPath and keep a track of which one is selected. I would recommend something like so:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [tableview cellAtIndex:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryCheckmark)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
}
note: I did not test this, but should give you the basic idea. Let me know if you have any questions. Did you try using a default uitableviewcell and see if it did the checkmark? I would not think a subclass would have a problem, as long as you are not modifying in the subclass.
Another option is to use tableView:didDeselectRowAtIndexPath: in addition to tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}