Reload UITableView data not working properly - ios

I have an array objects received from my webservice that I use to populate a UITableView. I'm trying to implement a method that gets a new array from the webservice and redefines my array that populates the table and then reload the tableView to use the new objects from this array.
This is the method that should do the work:
WSCaller *caller = [[WSCaller alloc]init];
arrayFromWS = [caller getArray];
[self.table reloadData];
and it doesn't work. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"productsCellIdentifier";
ProductsCell *cell = nil;
cell = (ProductsCell *)[self.table dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle]loadNibNamed:#"ProductsCell" owner:nil options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[ProductsCell class]])
{
cell = (ProductsCell *)currentObject;
break;
}
}
}
if (productsMutableArray)
{
cell.backgroundColor = [UIColor whiteColor];
cell.productName.text = [[self.productsMutableArray objectAtIndex:indexPath.row]objectForKey:#"name"];
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [productsMutableArray count];
}

Your datasource implementation is wrong (or at least the snippets are).
First, you aren't retaining the arrayFromWS:
WSCaller *caller = [[WSCaller alloc] init];
arrayFromWS = [caller getArray];
[self.table reloadData];
Second, on your tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: methods, you're using a different array (productsMutableArray).
To fix that, I'd recommend to change the code above for something like (assuming that your productsMutableArray is a strong/retain property:
WSCaller *caller = [[WSCaller alloc] init];
self.productsMutableArray = [NSMutableArray arrayWithArray:[caller getArray]];
[self.table reloadData];

Related

Search bar works correctly but crashes when I want to set table cell label

I am trying to implement a search bar with my table view. Both my table view and search bar are placed using storyboard. In my ViewDidLoad, I have:
self.searchDisplayController.delegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.searchResultsDelegate = self;
and implemented two search methods:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"nickname contains[cd] %#",searchText];
NSArray* array = [[NSArray alloc]init];
array = [self.fbfriendList filteredArrayUsingPredicate:bPredicate];
self.searchResult = [NSMutableArray arrayWithArray:array];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
In my table view method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"addFriend";
cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FFAddFriendTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (tableView == self.searchDisplayController.searchResultsTableView)
{
NSLog(#"!!! %#",self.searchResult);
if (cell == nil) {
[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:#"FFAddFriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"addFriend"];
}
else{
NSLog(#"!!! %#",self.searchResult);
// LINE XXXXXXX
cell.nameLabel.text = [[self.searchResult objectAtIndex:indexPath.row] objectForKey:#"nickname"];
}
}
else
{
}
cell.nameLabel.text = [[self.fbfriendList objectAtIndex:indexPath.row] objectForKey:#"nickname"];
return cell;
}
Everything works accordingly in terms of search. My NSLogs prints out the correct data in my array. However, when I want to set the cell's label according to the data from the NSMutableArray, it crashes with the error:
-[__NSCFString setText:]: unrecognized selector sent to instance 0x7ff38b5b70e0
Am I missing any crucial fundamental to implementing the search bar to my tableView?
In the line below "// LINE XXXXXX", you have,
cell.nameLabel = ...
That should be,
cell.nameLabel.text = ...
now change your table view cellrowindex Method to this..
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"addFriend";
cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FFAddFriendTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.nameLabel.text = [[self.searchResult objectAtIndex:indexPath.row] objectForKey:#"nickname"];
} else
{
cell.nameLabel.text = [[self.fbfriendList objectAtIndex:indexPath.row] objectForKey:#"nickname"];
}
return cell;
}

Loading data from cell to detailView always show the last data

I have UITableView with some data from backend, I have everything in table,3 UILable and I will get that information from backend and I can show them in table row, when I click on row I want to have the same label in my detail view, but now, I have just one information in all my detail view, same information, just load the last row for all detailView,
would you please help me in this implementation,
Thanks in advance!
cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"BooksCell";
BooksCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell =[ [[NSBundle mainBundle] loadNibNamed:#"BooksCell" owner:nil options:nil]
lastObject];
}
_books = [server get_tests:10 offset:0 sort_by:0 search_for:#""];
_t = [NSMutableString stringWithFormat:#"%# ", [_books objectAtIndex:indexPath.row]];
NSString *testdata = _t;
_components = [testdata componentsSeparatedByString:#","];
NSLog(#"_components: %#",_components);
for (NSString *aComponent in _components) {
if ([aComponent hasPrefix:#"title"]) {
_subComponents = [aComponent componentsSeparatedByString:#":"];
_titleString = [_subComponents[1] stringByTrimmingCharactersInSet:[NSCharacterSet
characterSetWithCharactersInString:#"\""]];
}if ([aComponent hasPrefix:#"authors"]){
_subComponents = [aComponent componentsSeparatedByString:#":"];
_writerString = [_subComponents[1] stringByTrimmingCharactersInSet:[NSCharacterSet
characterSetWithCharactersInString:#"\""]];
}if ([aComponent hasPrefix:#"name"]){
_subComponents = [aComponent componentsSeparatedByString:#":"];
_publisherString = [_subComponents[1] stringByTrimmingCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"\""]];
break;
}
}
cell.bookTitle.text = _titleString;
cell.writer.text = _writerString;
cell.publisher.text = _publisherString;
return cell;
}
didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
BooksDetailView *c = [[BooksDetailView alloc] init];
[self.booksTable addSubview:c.view];
c.bDetailTitle.text = _titleString;
c.bDetailWriter.text = _writerString;
c.bDetailPublisher.text = _publisherString;
}
_titleString, _writerString and _publisherString seem to be instance variables
of the table view controller, and these are overwritten in cellForRowAtIndexPath
each time a cell is displayed.
You have to use the indexPath in didSelectRowAtIndexPath to get the correct element
of your data source.
Note also that fetching all elements from the server in cellForRowAtIndexPath
is very ineffective, because this method is called frequently.
You should fetch the data once (e.g. in viewDidLoad) and assign
the fetched array to an instance variable or property of the view controller.
Then you can access the elements from the array in cellForRowAtIndexPath and in
didSelectRowAtIndexPath.
Add a property
#property (strong, nonatomic) NSArray *books;
to the view controller. Fetch the data in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.books = [server get_tests:10 offset:0 sort_by:0 search_for:#""];
// ... other stuff ...
}
In cellForRowAtIndexPath you just get the element from the array.
Also, instead of all that string manipulation, you should use the model class
and property accessors generated by the Thrift API.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"BooksCell";
BooksCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell =[[[NSBundle mainBundle] loadNibNamed:#"BooksCell" owner:nil options:nil] lastObject];
}
YourModelClass *book = self.books[indexPath.row];
cell.bookTitle.text = book.title;
// ...
return cell;
}
And similarly in didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
BooksDetailView *c = [[BooksDetailView alloc] init];
[self.booksTable addSubview:c.view]; // WHY THAT?
YourModelClass *book = self.books[indexPath.row];
c.bDetailTitle.text = book.title;
// ...
}

Objective-C : Table cell just returns last information of matching data

I'm trying to insert data into the rows I've created, I will get all info in my Log but it only shows the last info in all of my rows. Could anyone suggest a way to avoid this error?
Please offer me some advice thanks!
You are never re-populating the cells, actually. You are creating the initial visible cells, and just reusing them with the same content.. please look below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"TestCell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// HERE YOU ONLY WANT TO INSTANTIATE THE CELL
NSArray *topObjects = [[NSBundle mainBundle] loadNibNamed:#"TestCell" owner:nil options:nil];
for (id currentObject in topObjects)
{
if([currentObject isKindOfClass:[TestCell class]])
{
cell = (TestCell *) currentObject;
break;
}
}
}
// HERE YOU WOULD ACTUALLY POPULATE THE CELL WITH DATA
NSArray *array = [server get_texts:10 offset:0 sort_by:0 search_for:#""];
NSMutableString *s = [[NSMutableString alloc] init];
for (testMetaData *m in array){
[s appendFormat:#"%# %# \n", m.title,m.note];
cell.title.text = m.title;
NSLog(#" title %# ", m.title);
}
return cell;
}
Some info about UITableView:
So, a properly setup tableView only allocates and uses a limited number of UITableViewCells. After allocating, say 5 cells (this number is determined by "How many cells can you see at any given time?"), it will take an already created cell that has been scrolled out of the visible area, and gives it back to you in that method you are using, so you can re-populate it. So, cell variable will not be nil at that time, and your server code never gets called.
I think it has to do with your for loop.
NSMutableString *s = [[NSMutableString alloc] init];
for (testMetaData *m in array){
[s appendFormat:#"%# %# \n", m.title,m.note];
cell.title.text = m.title;
NSLog(#" title %# ", m.title);
}
Your cell.title.text = m.titlewill get the last m.title info at the end of the for loop.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
//Load Cell for reuse
static NSString *CellIdentifier = #"TestCell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell =[ [[NSBundle mainBundle] loadNibNamed:#"TestCell" owner:nil options:nil] lastObject];
}
//appending text and config cell
NSArray *array = [server get_texts:10 offset:0 sort_by:0 search_for:#""];
NSString *t = [array objectAtIndex:indexPath.row];
//Config cell - Not sure what you want. Maybe 10 different rows
cell.title.text = t;
return cell;
}

didselectrowatindexpath not called

I am facing a problem where the didselectrowatindexpath is not getting called.
My tableview is set in viewdidload as follows:
- (void)viewDidLoad
{
//[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView reloadData];
self.detailViewController = (klViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
Now my cellForRowAtIndexPath gets called and I am reusing the cells as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"menuSelection1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
AmbassadorInfoData * data = [self.LoadMenuItems objectAtIndex:indexPath.row];
cell.textLabel.text = data.treeName;
return cell;
}
I have checked other answers and mostly said that there could be the use of didDeselectRowAtIndexPath might be used. But this is not the case here.
Now my problem is in my split view controller whenever I select any option the corresponding detail view doesn't get displayed and is blank. None of my methods in the rootview controller (klViewController) gets called. What could be the reason for this?
Following are the all methods related to UITableView. It is implemented in the same class as in viewDidLoad
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.LoadMenuItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"menuSelection1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
AmbassadorInfoData * data = [self.LoadMenuItems objectAtIndex:indexPath.row];
cell.textLabel.text = data.treeName;
return cell;
}
-(NSArray *)LoadMenuItems
{
NSMutableArray * menuData = [[NSMutableArray alloc] initWithCapacity:5];
AmbassadorInfoData * data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Ambassador Info";
data.treeDescription = #"This is temp data.";
NSString * file = [[NSBundle mainBundle] pathForResource:#"oak" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"AmbassadorInternalList";
data.treeDescription = #"This is temp data.).";
file = [[NSBundle mainBundle] pathForResource:#"DouglasFir" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 3";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"SugarMaple" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 4";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"RedMaple" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 5";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"Pine" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
menuItems = [[NSArray alloc] initWithArray:(NSArray *)menuData];
data=nil;
return menuItems;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AmbassadorInfoData * selectedItem =(AmbassadorInfoData *)[self.menuItems objectAtIndex:[self.tableView indexPathForSelectedRow].row];
detailObject = selectedItem;
[detailViewController setDetailItem:detailObject];
}
#end
It could be that your program is stuck in a long running operation because of the way you're using LoadMenuItems. Every time numberOfRowsInSection and cellForRowAtIndexPath is called, you're recreating the entire array -- this is bad. You should call LoadMenuItems once, in viewDidLoad perhaps, and once you've created that array, use it, not a call to LoadMenuItems when you need to get data out. I don't know if this is what is causing your problem, but you should definitely fix it, and see if it makes a difference.
Try these modifications:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"TableView methods are called! problem is getting AmbassadorInfoData object")
AmbassadorInfoData * selectedItem =(AmbassadorInfoData *)[self.menuItems objectAtIndex:indexPath.row];
if (!selectedItem) NSLog(#"Unable to get Ambassador object, check your menuItems");
[self.detailViewController setDetailItem:selectedItem]; //notice "self."
}
also, uncomment [super viewDidLoad];
EDIT:
it appears that you are using the code you don't understand, in this case i am suggesting to learn some basics....here's a great site that helped me understand things quite a few times
and this is a guide from Apple: Table View Programming Guide

Data Lost after scroll in UITableView

I am trying to display plist data in tableview.
My problem is that after scrolling down i lost my previously fetched data.
Actually i am using custom cell so i think this is happen.
Code for Source and delegate of table is below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellID = #"Cell";
OffersCustomCell *cell = (OffersCustomCell *)[mytableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"OffersList" ofType:#"plist"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"OffersCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.titleLabel.font = [UIFont fontWithName:#"Formata-Regular" size:13.0f];
cell.saveLabel.font = [UIFont fontWithName:#"Formata-Bold" size:14.0f];
cell.nowLabel.font = cell.titleLabel.font;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *dict = [tableData objectAtIndex:indexPath.row];
NSLog(#"%#",dict);
cell.titleLabel.text = [dict objectForKey:#"title"];
cell.nowLabel.text = [dict objectForKey:#"price"];
cell.saveLabel.text = [dict objectForKey:#"rondel"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[mytableView deselectRowAtIndexPath:indexPath animated:YES];
}
Did you set the height for each cell
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 0;
//calculate height for each cell
return height;
}
Use this UITableView delegate method to set height of the cells.
you can use another class that is store your data and reload time you used that class and restore your data correctly and efficiently.
I solved it. :)
only problem is no retaining memory for UItableview.
tableData = [[NSArray arrayWithObjects:[dic objectForKey:#"Response"], nil] retain];

Resources