UITableView scroll is never end after search - objective-c

I have UITableView to show whole bunch of words from array.
I also provide search bar on top of table view so when people type a word in textbox search then my code start filtering data from array.
My result is good but my scroll in tableview is never end even though there is only one row.
My tableview result can scroll down and down without no row.
I don't know what going on with my table view.
My code that I have implement.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(self.tableView == tableView){
return [self.alphabet count];
}else{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.tableView == tableView) {
return [[self.vocabularyInfo objectAtIndex:section] count];
}else{
return [self.filteredVocabs count];
}
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.alphabet objectAtIndex:section];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
if(self.tableView == tableView){
return self.alphabet;
}else{
return nil;
}
}
// Display cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"CommentTableCell";
//-- try to get a reusable cell --
CommentTableCell *cell = (CommentTableCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//-- create new cell if no reusable cell is available --
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
VocabularyController *vc;
// Display word from database else display vocabulary when searching
if (tableView != self.searchDisplayController.searchResultsTableView) {
vc = [self.vocabularyInfo[indexPath.section] objectAtIndex:indexPath.row];
}else{
vc = [self.filteredVocabs objectAtIndex:indexPath.row];
}
cell.nameLabel.text = vc.korean;
return cell;
}
// My method that I used for filtering my array to display the result
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
if (searchString.length > 0) {
NSArray *vocabToSearch = self.vocabularyInfo;
if (self.currentSearchString.length > 0 && [searchString rangeOfString:self.currentSearchString].location == 0) {
vocabToSearch = self.filteredVocabs;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"korean CONTAINS[cd] %#", searchString];
self.filteredVocabs = [vocabToSearch filteredArrayUsingPredicate:predicate];
} else {
self.filteredVocabs = self.vocabularyInfo;
}
self.currentSearchString = searchString;
return YES;
}
Please help me!!

Check your tableview's datasource delegate function.
Maybe more detail about your implementation is helpful.

Please check the value you are returning for the number of rows in the following method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

Related

want to check only one tablecell at a time in TableView

In the source code below I am able to change my checkmark object value, but at the time of reload data in cellForRowAtIndexPath method it shows old data:
//TableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [self.tableData count];
}
//CellforRowAtIndexpath showing old table data
- (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];
}
Recipe *obj = nil;
obj = self.tableData[indexPath.row];
cell.textLabel.text = obj.name;
NSLog(#"Reload Data %#", obj.checkmark);
if ([obj.checkmark integerValue] == 1)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = nil;
recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
//recipe.checkmark=#"1";
for (int i=0; i<[self.tableData count]; i++) {
if (i==indexPath.row) {
recipe.checkmark=#"1";
}
else{
recipe.checkmark=#"0";
}
NSLog(#"PK ! %#", recipe.checkmark);
}
}
//[self.tableData addObject:recipe.checkmark];
[self.myTable reloadData];
[self.myTable reloadData];
}
The good news is normally this issue is in the cell for row logic, but it looks like you have that portion right. I believe the issue is in your cell for row logic because you are not updating tableData correctly. See extra comments below.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = nil;
recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
//This only gets called if current checked cell is already checked
for (int i=0; i<[self.tableData count]; i++) {
if (i==indexPath.row) {
recipe.checkmark=#"1";
}
else{
//This is still the recipe for the cell currently selected
recipe.checkmark=#"0";
}
NSLog(#"PK ! %#", recipe.checkmark);
}
}
//[self.tableData addObject:recipe.checkmark];
[self.myTable reloadData];
[self.myTable reloadData];
}
Something like this should fix your issue without changing too much of your code or structure.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
recipe.checkmark=#"1";
}
//remove all old checkmarks
for (int i=0; i<[self.tableData count]; i++)
{
//Only update recipes that are not in this row
if (i!=indexPath.row)
{
recipe = [self.tableData objectAtIndex:i];
recipe.checkmark=#"0";
}
}
[self.myTable reloadData];
}
Another things to consider is instead of using a string that you are converting to an integer that is acting like a BOOL just change recipe's property checkmark to a BOOL. I hope that helps and good luck.

Filtered data doesn't show in my UITableView Objective C iOS7

I am trying to bind "Search Bar and Search Display Controller" in my UITableView. Filtered array has the right data but it doesn't display in tableview. When I enter something in search bar it displays blank table view.
In function "cellForRowAtIndexPath" when it binds the correct data but still doesn't show up. In the same function I also changed the code from
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell" forIndexPath:indexPath];
to
UITableViewCell *cell = [self.personTableView dequeueReusableCellWithIdentifier:#"PersonCell" forIndexPath:indexPath];
then it throws the following exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person length]: unrecognized selector sent to instance 0x1780ca170'
Code:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.filteredPersonArray count];
} else {
return [self.personArray count];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell" forIndexPath:indexPath];
Person *person;
if (tableView == self.searchDisplayController.searchResultsTableView) {
person = (Person *)[self.filteredPersonArray objectAtIndex:indexPath.row];
} else {
person = (Person *)[self.personArray objectAtIndex:indexPath.row];
}
UILabel *nameLabel = (UILabel *)[cell viewWithTag:1];
nameLabel.text = [NSString stringWithFormat:#"%# %#", person.firstName, person.lastName];
// so on;
return cell;
}
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredPersonArray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *lastNamepredicate = [NSPredicate predicateWithFormat:#"SELF.lastName contains[c] %#",searchText];
//NSPredicate *firstNamePredicate = [NSPredicate predicateWithFormat:#"SELF.firstName contains[c] %#",scope];
//tempArray = [tempArray filteredArrayUsingPredicate:lastNamepredicate];
self.filteredPersonArray = [NSMutableArray arrayWithArray:[self.personArray
filteredArrayUsingPredicate:lastNamepredicate]];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:
[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
Solution to this problem:
I referred to different tableview objects while creating the cell in case of
1. Loading the data after search
2. Loading the data in tableview
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
Person *person;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell = [self.personTableView dequeueReusableCellWithIdentifier:#"PersonCell"];
person = (Person *)[self.filteredPersonArray objectAtIndex:indexPath.row];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell"];
person = (Person *)[self.personArray objectAtIndex:indexPath.row];
}
UILabel *nameLabel = (UILabel *)[cell viewWithTag:1];
nameLabel.text = [NSString stringWithFormat:#"%# %#", person.firstName, person.lastName];
// so on;
return cell;
}

TableView not reloading properly

I am making an settings screen in which you can select stations via a uisearchbar. I have a sectioned tableview, with the first letter of a station as the header and every station is categorized by it's first letter. So far so good.
I habe 2 NSMutableArray's with, per section, the stations. One is the unfiltered array (Which I use when I don't have it filtered) and the other one, when I am searching for something. (I do this via a predicate). On every keypress on the keyboard I do a [self.tableView reloadData]; this works, HOWEVER the scrollview stays too long! So you can scroll way past how many results are actually in the selected array. This causes a crash, because it's trying to get objects that don't exist.
So it seems like the tableview isn't counting the array right or something?
Is anyone familiar with this problem?
Here is some code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (self.searching) {
return [self.tableFilterd count];
} else {
return [self.tableData count];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Rows for section");
// Return the number of rows in the section.
if (self.searching) {
NSLog(#"Editing section: %i, count %i", section, [[self.tableFilterd objectAtIndex:section] count]);
return [[self.tableFilterd objectAtIndex:section] count];
} else {
NSLog(#"Not editing");
return [[self.tableData objectAtIndex:section] count];
}
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
SettingsHeaderCell *cell = [[[SettingsHeaderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"HeaderCell"] autorelease];
cell.labelLetter.text = [[self.tableLetters objectAtIndex:section] capitalizedString];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 52;
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
SettingsCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[SettingsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (self.searching) {
StationObject *object = (StationObject *)[[self.tableFilterd objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
[cell setStationObject:object];
} else {
StationObject *object = (StationObject *)[[self.tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
[cell setStationObject:object];
}
return cell;
}
You might have solved this by now but I suspect you aren't emptying either arrays. In the method:
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
//Remove all objects first
[self.tableFiltered removeAllObjects];
[self.tableData removeAllObjects];
Also you only need to call [self.tableView reloadData]; in textDidChange, not in the other three methods. Hope this helps.

UISearchDisplayController Not Displaying Results in searchResultsTableView

I have a UISearchDisplayController properly connected to the header of a custom UITableView in IB. However, when I search for anything the searchResultsTableView only displays "No Results", and I cannot seem to find where the code is incorrect.
searchResults Property
- (NSMutableArray *)searchResults {
if (!_searchResults) {
_searchResults = [[NSMutableArray alloc] initWithCapacity:self.listingPreviews.count];
}
return _searchResults;
}
Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSInteger numberOfRows = 0;
if (tableView == self.tableView) {
numberOfRows = self.listingPreviews.count;
} else {
numberOfRows = self.searchResults.count;
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[ListingPreviewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Search Bar Delegate Method
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSInteger searchTextLength = searchText.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchTextLength) && ([listingPreview.title rangeOfString:searchText].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
}
Just try this instead:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Please note that the change was applied on:
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
This way you deque a Cell from your own tableView and not from the one created by UISearchDisplayController.
It seems that nothing in your code forces searchDisplayController to reload it's searchResultTableView.
The standard approach is to set UISearcDisplayController's delegate (note the protocol - UISearchDisplayDelegate) and implement – searchDisplayController:shouldReloadTableForSearchString:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// perform your search here and update self.searchResults
NSInteger searchStringLength = searchString.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchStringLength) && ([listingPreview.title rangeOfString:searchString].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
// returning YES will force searchResultController to reload search results table view
return YES;
}

Populating UITableView from NSMutableArray

I am experiencing a strange issue with this code.
- (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] autorelease];
}
// Configure the cell...
if (accounts != nil) {
NSLog(#"Cell: %#", indexPath.row);
cell.textLabel.text = [self.accounts objectAtIndex: indexPath.row];
}
else
{
NSLog(#"No cells!");
[cell.textLabel setText:#"No Accounts"];
}
return cell;
}
My table view populates just fine, except all rows contain the first item in my NSMutableArray, accounts. I am logging the value of indexPath.row and it remains at (null) no matter how many values are in the array. Am I doing something wrong here?
I don't believe this! I am bonking myself on the head for not finding this sooner!
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [accounts count]; //<--This is wrong!!!
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1; // <--This needs to be switched with the error above
}
The above code was the reason why it was printing the same row in my array twice, rather than marching forward in my array.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [accounts count];
}
This code is correct and produces the proper result. What a fuster cluck. ^^;
Should be #"%i", indexPath.row not #"%#", indexPath.row
Also I recommend putting this at the top of your method:
NSUInteger row = [indexPath row];
Then your method looks like this:
// Cell Ident Stuff
// Then configure cell
if (accounts) {
NSLog(#"Cell: %i", row);
cell.textLabel.text = [self.accounts objectAtIndex:row];
}
else {
NSLog(#"No accounts!");
// Only setting for the first row looks nicer:
if (row == 0) cell.textLabel.text = #"No Accounts";
}
It's good practice when dealing with table view methods. Try that.