Edited code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil)
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if (isFiltered) {
int rowCount=indexPath.row;
Aves *filtrada=[filteredTableData objectAtIndex:rowCount];
cell.textLabel.text=filtrada.name;
NSLog(#"mostrando: ");
}else {
int rowCounter=indexPath.row;
Aves *author=[theauthors objectAtIndex:rowCounter];
cell.textLabel.text=author.name;
}
NSLog(#"mostrando: ");
return cell;
}
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
isFiltered = true;
int i;
[filteredTableData removeAllObjects];
for(i=0;[theauthors count]>i;i++)
{
Aves *name=[theauthors objectAtIndex:i];
//NSLog(name.name);
NSRange nameRange = [[name.name lowercaseString] rangeOfString:[text lowercaseString]];
if(nameRange.length>0)
{
[filteredTableData addObject:name];
NSLog(name.name);
}
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
}
Edit: After working on it a while I solved some problems.Just updated my code, the problem is the repaint of the tableView, every thing else go ok. Check it and give any ideas you have plz ^^
Thx again for your time.
I assume you're using prototype cells? I just had a similar problem in one of my projects.
When search results are displayed and tableView:cellForRowAtIndexPath: is called, the table view passed in the the table belonging to the search results controller, not your main table view. Problem with that is, the search results table view doesn't know anything about your table's prototype cells, so dequeueReusableCellWithIdentifier: returns nil. But just alloc/init'ing a UITableCellView won't give you one of your prototype cells, so whatever UI you laid out in your storyboard isn't there.
The fix is easy: in tableView:cellForRowAtIndexPath:, don't call dequeueReusableCellWithIdentifier: on the tableview passed in; just call it on your main table view. So basically, just change this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil)
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
to this:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
There's no need for the nil check; Apple's Storyboards Release Notes says:
The dequeueReusableCellWithIdentifier: method is guaranteed to return
a cell (provided that you have defined a cell with the given
identifier). Thus there is no need to use the “check the return value
of the method” pattern as was the case in the previous typical
implementation of tableView:cellForRowAtIndexPath:.
does your app hits this code if(nameRange.location ==0) ?
Change the code piece of
else
{
isFiltered = true;
int i=0;
[filteredTableData removeAllObjects];
filteredTableData = [[NSMutableArray alloc] init];
//for (Aves* name in theauthors)
for(i=0;[theauthors count]>i;i++)
{
Aves *name=[theauthors objectAtIndex:i];
NSRange nameRange = [name.foodName rangeOfString:text ];
if(nameRange.location ==0)
{
[filteredTableData addObject:name];
}
[self.tableView reloadData];
}
}
to
else
{
isFiltered = true;
int i=0;
[filteredTableData removeAllObjects];
//filteredTableData = [[NSMutableArray alloc] init]; not needed
//for (Aves* name in theauthors)
for(i=0;[theauthors count]>i;i++)
{
Aves *name=[theauthors objectAtIndex:i];
NSRange nameRange = [name.foodName rangeOfString:text ];
if(nameRange.location != NSNotFound)
{
[filteredTableData addObject:name];
}
}
[self.tableView reloadData];
}
use this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//If the requesting table view is the search display controller's table view, return the count of the filtered list, otherwise return the count of the main list.
if (isFiltered)
{
return [filteredTableData count];
}
else
{
return [theauthors count];
}
}
Replace method:
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
isFiltered = true;
int i=0;
[filteredTableData removeAllObjects];
filteredTableData = [[NSMutableArray alloc] init];
//for (Aves* name in theauthors)
for(i=0;[theauthors count]>i;i++)
{
Aves *name=[theauthors objectAtIndex:i];
NSRange nameRange = [[name.foodName lowercaseString] rangeOfString:[text lowercaseString]];
if(nameRange.length>0)
{
[filteredTableData addObject:name];
[self.tableView reloadData];
}
}
}
}
finally fixed it. Here is my working code, thx you all =)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
if (isFiltered==TRUE) {
int rowCount=indexPath.row;
//for (rowCount=0; rowCount<[filteredTableData count]; rowCount++) {
Aves *filtrada=[filteredTableData objectAtIndex:rowCount];
cell.textLabel.text=filtrada.name;
//}
}else if(isFiltered==FALSE)
{
int rowCounter=indexPath.row;
Aves *author=[theauthors objectAtIndex:rowCounter];
cell.textLabel.text=author.name;
}
return cell;
}
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text {
[filteredTableData removeAllObjects];
filteredTableData=[[NSMutableArray alloc]init ];
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
isFiltered = TRUE;
int i;
for(i=0;[theauthors count]>i;i++)
{
Aves * filtrado=[[Aves alloc]init];
filtrado=[theauthors objectAtIndex:i];
//NSLog(filtrado.name);
NSRange nameRange = [[filtrado.name lowercaseString] rangeOfString:[text lowercaseString]];
if(nameRange.length>0)
{
[filteredTableData addObject:filtrado];
}
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil
waitUntilDone:NO];
}
}
You probably want to replace
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
with in your cellForRowAtIndexPath
UITableViewCell *cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
The reason because you're not getting use of the dequeued cell anyway.
Related
I have allSpecialities array, and selectedSpecialities array. I'm downloading those arrays from the server, parse them to object and adding them to those arrays. Now, I want to check/uncheck some specialities. I've tried with containsObject, but that's not working, because those objects are not on the same memory location. This is code that I've done so far, and it's working, but I have problem how to add them to this array.
in cellForRowAtIndexPath:
for (Speciality *specTemp in self.selectedSpecialities) {
if (speciality.specialityId == specTemp.specialityId) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
in didSelect:
Speciality *speciality = [[Speciality alloc]init];
speciality = self.allSpecialities[indexPath.row];
NSMutableArray *tempSelectedSpecialities = [[NSMutableArray alloc]initWithArray:self.selectedSpecialities];
int i=0;
for (Speciality *tempSpeciality in tempSelectedSpecialities) {
if (tempSpeciality.specialityId == speciality.specialityId) {
[self.selectedSpecialities removeObjectAtIndex:i];
}
else {
}
i++;
}
[self.delegate companySpecialities:self.selectedSpecialities];
[self.specialitiesTableView reloadData];
I have declare one Mutable array in .h to store a data
NSMutableArray *selectedMarks;
assign memory in viewDidLoad
selectedMarks = [NSMutableArray new];
add and remove object in didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = (TableViewCell *)[self.tblview cellForRowAtIndexPath:indexPath];
NSString *strIndex=[NSString stringWithFormat:#"%ld",(long)indexPath.section];
if ([selectedMarks containsObject:strIndex])// Is selected?
{
[selectedMarks removeObject:strIndex];
}
else{
[selectedMarks addObject:strIndex];
}
}
in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CRTableViewCellIdentifier = #"TableViewCell";
TableViewCell *cell = (TableViewCell *)[self.tblview dequeueReusableCellWithIdentifier:CRTableViewCellIdentifier];
if (cell == nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CRTableViewCellIdentifier];
}
cell.backgroundColor=[UIColor colorWithRed:122/255.0 green:196/255.0 blue:251/255.0 alpha:1];
// Check if the cell is currently selected (marked)
NSString *txtQRCodeid = [[[dictListQR objectForKey:#"boxlist"]objectAtIndex:indexPath.section]valueForKey:#"qr_code_id"];
NSString *text1 = [[[dictListQR objectForKey:#"boxlist"]objectAtIndex:indexPath.section]valueForKey:#"box_name"];
NSString *text=[NSString stringWithFormat:#"QR Code %ld with %#",indexPath.section+1,text1];
cell.isSelected = [selectedQR containsObject:txtQRCodeid] ? YES : NO;
if (cell.isSelected) {
[cell.btnSelection setImage:[UIImage imageNamed:#"check"] ];
// set image of selected
}
else{
[cell.btnSelection setImage:[UIImage imageNamed:#"uncheck"] ];
// set unselected image
}
cell.lblQRcodeText.text=text;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
return cell;
}
It's Work for me
I am trying to save the checkmark that i place on a cell and then retrieve it. I have 11 cells in that section.
I tried to use this link as a guide and it works. But i want only need one checkmark to be saved rather than many.
And also i want to set checkmark for all cells by default. How would i achieve this
My Code :
- (NSString *)getKeyForIndex:(int)index{
return [NSString stringWithFormat:#"KEY%d",index];
}
- (BOOL) getCheckedForIndex:(int)index {
if([[[NSUserDefaults standardUserDefaults] valueForKey:[self getKeyForIndex:index]] boolValue]==YES) {
return YES;
}
else
{
return NO;
}
}
- (void) checkedCellAtIndex:(int)index
{
BOOL boolChecked = [self getCheckedForIndex:index];
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:!boolChecked] forKey:[self getKeyForIndex:index]];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (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];
if(section == 4) {
if([self getCheckedForIndex:indexPath.row]==YES) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = nil;
NSString *key = [_keys objectAtIndex:indexPath.section];
NSArray *name = [_names objectForKey:key];
static NSString *MyCellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyCellIdentifier];
cell.textLabel.text = [name objectAtIndex:indexPath.row];
if(section == 4) {
[self checkedCellAtIndex:indexPath.row];
if([self getCheckedForIndex:indexPath.row]==YES)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Solution can be tricky :
Maintain one array same to tableview datasource array.
Say for example u have NSMutableArray *mutArrNames which tableview datasource. Now NSMutableArray *mutArrNamesCheckListwhich shows which one is checked or not;
Intially nothing is selected so add 0 to uncheck one:
for(int i =0; i<[mutArrNames count];i++)
{
[mutArrNamesCheckList addObject:#"0"];
}
Now use like this:
- (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];
if(section == 4) {
//check from mutArrNamesCheckList's list if cell is check one or not
if([[mutArrNamesCheckList objectAtIndex:indexPath.row] intValue] == 1) //checked one
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else //unchecked one
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
}
return cell;
}
Here it can be used according to your requirement like allow mutiple selection or single selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//get cell object
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(section == 4)
{
if([[mutArrNamesCheckList objectAtIndex:indexPath.row] intValue] == 1) //checked one
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//replace 0 with 1 as check one
[mutArrNamesCheckList replaceObjectAtIndex:indexPath.row withObject:#"0"];
}
else //unchecked one
{
cell.accessoryType = UITableViewCellAccessoryNone;
//replace 1 with 0 as uncheck one
[mutArrNamesCheckList replaceObjectAtIndex:indexPath.row withObject:#"1"];
}
}
}
For selection and unselection of all cell add this in button's action method. Use this :
//remove all as new objects will be added
[mutArrNamesCheckList removeAllObjects];
if(!btnCheckAll.selected)//selected property used - default is no so all not selected
{
//make all selected
for(int i =0; i<[mutArrNames count];i++)
{
[mutArrNamesCheckList addObject:#"1"];
}
//change buttons image here
}
else
{
//make all unselected
for(int i =0; i<[mutArrNames count];i++)
{
[mutArrNamesCheckList addObject:#"0"];
}
//change buttons image here
}
//tableView reload
[yourtableView reloadData];
btnCheckAll.selected = !btnCheckAll.selected;
Add mutArrNamesCheckList in AppDelegate to be visible in whole Application.
So remove iteration we done on top of above answer in our viewcontroller as we didn't wanted to use gobally
EDIT : added toggling in didSelectRowAtIndexPath + clicked select all button, all cell is checked else unchecked
I have implemented the search functionality as below. I am able to retrieve the rows based on search string but they are empty, when i click on the empty search result cell am able to navigate correctly for each search result.I am using story board configured cells to display the table. I mean am using tags in order to populate the data and the images.
- (void)viewDidLoad
{
sqlDatabase = [SQLiteDatabase getDatabaseInstance];
filteredItemist=[[NSMutableArray alloc] initWithArray:[sqlDatabase fetchCropListBySoilName:soilName]];
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell...
Crop * crop = [filteredItemist objectAtIndex:[indexPath row]];
NSString* str = [NSString stringWithFormat:#"%#.jpg",crop.cropName.lowercaseString];
UIImageView *cropImageView = (UIImageView *)[cell viewWithTag:100];
cropImageView.image = [UIImage imageNamed:str];
UILabel *cropNameLabel = (UILabel *)[cell viewWithTag:70];
cropNameLabel.text = [crop cropName];
return cell;
}
- (void)viewWillAppear:(BOOL)animated
{
self.navigationItem.title = #"Item List";
filteredItemist = [[NSMutableArray alloc]initWithArray:[sqlDatabase fetchCropListBySoilName:soilName]];
[self.tableView reloadData];
self.navigationController.toolbarHidden = YES;
[super viewWillAppear:animated];
}
- (void)filterContentForSearchText:(NSString*)searchText
{
if([searchText length] == 0)
{
isFiltered = FALSE;
[filteredItemist removeAllObjects];
[filteredItemist addObjectsFromArray:[sqlDatabase fetchCropListBySoilName:soilName]];
}
else{
isFiltered = TRUE;
[filteredItemist removeAllObjects];
for(Crop *i in [sqlDatabase fetchCropListBySoilName:soilName]){
NSRange stringRange = [[i cropName]rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(stringRange.location !=NSNotFound){
[filteredItemist addObject:i];
}
}
}
[self.tableView reloadData];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString];
return YES;
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self.searchBar resignFirstResponder];
}
Edit :
after changing the code to self.tableview :
Instead of this :
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
use this :
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Search results displayed in a separate table view. So if you use tableView without self you may be referring search results table view.
I have an app with a tableview which you can add and delete items though when I tried to implement a search bar it crashes whenever I type one letter. Here is the code that I am using:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
isFiltered = NO;
} else {
isFiltered = YES;
filteredPatients = [[NSMutableArray alloc] init];
for (Patient *patient in patients) {
NSRange patientNameRange = [patient.patientName rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (patientNameRange.location != NSNotFound) {
[filteredPatients addObject:patient];
}
}
}
[self.tableView reloadData];
}
This works fine though when you type a letter which has a patient in then it breaks at this line:
cell.textLabel.text = [filteredPatients objectAtIndex:indexPath.row];
Here is the code in context:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"cell"];
if ( nil == cell ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
NSLog(#"indexPath.row = %d, patients.count = %d", indexPath.row, patients.count);
Patient *thisPatient = [patients objectAtIndex:indexPath.row];
if (isFiltered == YES) {
cell.textLabel.text = [filteredPatients objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", thisPatient.patientName, thisPatient.patientSurname];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.textColor = [UIColor blackColor];
if (self.editing) {
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
return cell;
}
And returns this error
-[Patient isEqualToString:]: unrecognized selector sent to instance 0x756c180
If you want any more code then ask.
Thanks in advance
You are iterating on the collection patients that seems to contain Patient instances and not NSString instances. So I would do something like :
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
isFiltered = NO;
} else {
isFiltered = YES;
filteredPatients = [[NSMutableArray alloc] init];
for (Patient *patient in patients) {
NSRange patientNameRange = [patient.name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (patientNameRange.location != NSNotFound) {
[filteredPatients addObject:patient];
}
}
}
[self.tableView reloadData];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
MagazineListCell* cell=(MagazineListCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell==nil)
{
NSArray *arr=[[NSBundle mainBundle]loadNibNamed:#"MagazineListCell" owner:nil options:nil];
cell=(MagazineListCell *)[arr objectAtIndex:0];
[cell setDelegate:self];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
NSMutableArray *arr=[[NSMutableArray alloc]init];
NSInteger startIndex;
NSInteger endIndex;
if(isLandscape)
{
startIndex=indexPath.row*3;
if (startIndex+3>[self.arrMagazine count ])
{
endIndex=[self.arrMagazine count];
}
else
{
endIndex=startIndex+3;
}
}
else
{
startIndex=indexPath.row*2;
if (startIndex+2>[self.arrMagazine count])
{
endIndex=[self.arrMagazine count];
}
else
{
endIndex=startIndex+2;
}
}
for (int x=startIndex; x<endIndex; x++)
{
[arr addObject:[self.arrMagazine objectAtIndex:x]];
}
[cell setSelectedIndex:btnSegment.selectedSegmentIndex];
[cell contentForTableViewCell:arr setUIMode:isLandscape] ;
arr=nil;
return cell;
}
Check that your reuse identifier is being set as you may be creating the cell every time.
The main problem is probably going to be the array you're creating every time, looping around to populate and then passing on to the cell. You should try to do all of that setup before you need it.