I'm creating the UITableView datasource array using this code:
-(void) viewWillAppear:(BOOL)animated
{
// IBOutlet of tableview is 'editMsgTableView'
editMsgTableView.dataSource=nil;
editMsgTableView.delegate=nil;
menuMessageArray = [[NSMutableArray alloc] init];
editMainMenuMsgArray = [[NSMutableArray alloc] init];
menuMessageArray = [DBManager fetchmenu:0 noOfRows:32];
for(int i=0; i< [menuMessageArray count]; i++)
{
NSMutableDictionary *menuMsgListDic = [[NSMutableDictionary alloc] init];
menuMsgListDic = [menuMessageArray objectAtIndex:i];
[editMainMenuMsgArray addObject:menuMsgListDic];
}
editMsgTableView.dataSource=self;
editMsgTableView.delegate=self;
[editMsgTableView reloadData];
}
But it works for the first time. But whenever I do some tableView editing stuff or comes from another view controller,after that if viewWillAppearis called then reloadData is not working. I also tried:
dispatch_sync(dispatch_get_main_queue(), ^{
[editMsgTableView reloadData];
});
but not working. Please help me out.
When editing begins call [tableView startUpading]; and when editing is done, call [tableView stopUpdating]; then [tableView reloadData];.
Try ,
dispatch_async(dispatch_get_main_queue(), ^{
[editMsgTableView reloadData];
});
are you giving to that viewController the tableViewDelegates correctly? :
#interface theNameOfTheViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> in the .h file?
i suggest not to do this:
editMsgTableView.dataSource=nil;
editMsgTableView.delegate=nil;
editMsgTableView.dataSource=self;
editMsgTableView.delegate=self;
just this:
[self.editMsgTableView reloadData];
be sure that all the delegate methods are called when you use reloadData (put a breakpoint in every delegate method that should be used to reload the Data of the table when you make a change or the view Appears), remember that reloadData method, calls all delegate methods (if you´re giving to the view controller correctly the delegate as I said before) of the tableViewController. If nothing of this helps you, tell me.
I am assuming that you are navigating the view from one view to another view, then you should call [tableView reloadData] on ViewDidLoad.
This is because of the view life cycle - when you are coming back from one view and your tableView data source is updated, the view life cycle will be like this:
viewDidLoad
tableViewDelegateMethods
viewDidAppear
So when you update tableView's data source object and call reloadData during viewDidLoad will resolve the issue.
Related
I'm using a UICollectionView to display some data received from a remote server and I'm making two reloadData calls in a short time, first one to show a spinner (which is actually a UIActivityIndicatorView in a UICollectionViewCell) and the second one after the data was retrieved from server. I store the models based on which the collection view cells are created in a self.models NSArray and in cellForItemAtIndexPath I dequeue cells based on this model. My issue is that when I call reloadData after the request was completed (the second time) the collection view seems to be still in the process of creating the cells for the first reloadData call and it shows just the first two cells and a big blank space in place where the rest of the cells should appear.
I wrote some logs to get some insights of what's happening and the current workflow is:
I'm populating self.models with the model for the spinner cell and then I call reloadData on the UICollectionView.
numberOfItemsInSection is called, which is just returning [self.models count]. The returned value is 2, which is fine (one cell which acts like a header + the second cell which is the one with the UIActivityIndicator inside).
I'm making the request to the server, I get the response and I populate self.models with the new models received from the remote server (removing the model for the spinner cell but keeping the header cell). I call reloadData on the UICollectionView instance.
numberOfItemsInSection is called, which is now returning the number of items retrieved from the remote server + the model for the header cell (let's say that the returned value is 21).
It's just now when cellForItemAtIndexPath is called but just twice (which is the value returned by numberOfItemsInSection when it was called first).
It seems like the collection view is busy with the first reloadData when I call this method for the second time. How should I tell the collection view to stop loading cells for the first reloadData call? I tried with [self.collectionView.collectionViewLayout invalidateLayout] which seemed to work but the issue reappeared, so it didn't did the trick.
Some snippets from my code:
- (void)viewDidLoad {
[super viewDidLoad];
[ ...... ]
self.models = #[];
self.newsModels = [NSMutableArray array];
[self.collectionView.collectionViewLayout invalidateLayout];
[self buildModel:YES]; // to show the loading indicator
[self.collectionView reloadData];
[self updateNewsWithBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView.collectionViewLayout invalidateLayout];
[self buildModel:NO];
[self.collectionView reloadData];
});
}];
}
- (void) buildModel:(BOOL)showSpinnerCell {
NSMutableArray *newModels = [NSMutableArray array];
[newModels addObject:self.showModel]; // self.showModel is the model for the cell which acts as a header
if ([self.newsModels count] != 0) {
// self.newsModels is populated in [self updateNewsWithBlock], see below
[newModels addObjectsFromArray:self.newsModels];
} else if (showSpinnerCell) {
[newModels addObject:[SpinnerCellModel new]];
}
self.models = [NSArray arrayWithArray:newModels];
}
- (void) updateNewsWithBlock:(void (^)())block {
// Here I'm performing a GET request using `AFHTTPSessionManager` to retrieve
// some XML data from a backend, then I'm processing it and
// I'm instantiating some NewsCellModel objects which represents the models.
[ ..... ]
for (NSDictionary *item in (NSArray*)responseObject) {
NewsCellModel *model = [[NewsCellModel alloc] init];
model.itemId = [item[#"id"] integerValue];
model.title = item[#"title"];
model.headline = item[#"short_text"];
model.content = item[#"text"];
[self.newsModels addObject:model];
}
block();
}
called loadData method from other viewcontoller like:
TestTVC *testTVC = [[TestTVC alloc] init];
[testTVC loadData];
I put NSLog(#"testTVC Array section:%lu has %lu rows ") in numberOfRowsInSection, it return result.
However in the cellForRowAtIndexPath section, the NSLog(#"cellForRowAtIndexPath") never printed for somehow.
I was sure that my delegate and data source were set properly. Because it works when [self loadData]
I also try run it in the main thread, it does't work.
Does anyone knows? Thanks.
updated: i used [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone]; instead of [self.tableView reloaddata], it works but it didn't reload the UIImages in table cell.
NSLog(#"change cell image to testTVCImg1");
[testTVCCell.selectImgView setImage:[UIImage imageNamed:#"testTVCImg1"]];
the NSLog debug message printed, but the image didn't changed.
cellForRowAtIndexPath is called when a cell become visible.
When you do
TestTVC *testTVC = [[TestTVC alloc] init];
[testTVC loadData];
testTVC is not in the view hierarchy and its tableview neither. So cellForRowAtIndexPath won't be call.
In my app(Using Storyboards FYI) I have a viewController which contains a tableView. My viewController hits an API and returns an array of items that my tableView should populate with. The problem is, after successfully retrieving the array, the reloadData method does not trigger a call to cellForRowAtIndexPath. I've set the delegate and datasource properly, and still have no luck. Here is my code:
in my viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc]init];
self.tableView.dataSource = self;
self.tableView.delegate = self;
[[CCHTTPClient sharedClient] getItemsWithSuccess:^(NSArray *items) {
self.items = items;
[self.tableView reloadData];
} failure:^(NSError *error) {
}];
}
and also in my numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.items count];
}
I've also found that if i did an API call on the previous VC and set the array of the viewController's items before the viewController is pushed, the table populates properly. really unsure about what's going on here. Any help would be gratefully appreciated !
self.tableView should be an outlet if your controller and table view are made in a storyboard. You're creating a different table view in viewDidLoad with alloc init, so you're calling reloadData on that one, not the one you have on screen. Remove that alloc init line, and connect the outlet in IB.
I would suspect this is caused by calling reloadData from a secondary thread. Try this:
[[AGHTTPClient sharedClient] getItemsWithSuccess:^(NSArray *items) {
self.items = items;
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
} failure:nil];
I have the following method within a ViewController class:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:
(NSIndexPath *)indexPath
{
UITableViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
NSInteger tag = cell.tag;
// SEND TO SINGLE NEWS FEED TO DISPLAY THE INFORMATION OF THE VIDEO
singleNewsFeed* myScript = [[singleNewsFeed alloc] init];
[myScript startProcess:tag];
[self performSegueWithIdentifier:#"moveToSingleData" sender:self];
}
The receiver class:
- (void)startProcess:(NSInteger)number {
NSInteger check = number;
singlecellID = check;
// MAKE REQuEST TO SERVER
[self makeRequests];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
So what happens is that makeRequests runs and the tableView is refreshed. All methods for the tableView run except the cellForRowAtIndexPath
Here is the thing I know that all of these work properly because I have the same exact classes doing the same exact thing except they are sub viewcontrollers of a parent viewcontroller. I had the same exact issue and used self.parentViewController.childViewControllers[1]; to fix that when calling the method and it worked perfect. But this is different because this is a completely separate ViewController. So therefore I am not sure what to use to call that ViewController that allows cellForRowAtIndexPath to work correctly.
Suggestions, thoughts?
David
You're calling [self.tableView reloadData] but I don't think object you're calling it from is your table view controller. No?
I am new in objective-c developpment, I need to find a way to refresh my tableview.
I have 2 UIViewControllers, in the second one I insert data into my database and then I instantiate the first viewcontroller, it contains my tableview. I call a method that allows it to recover all of the data from the database, but when I use [tableview reloadData] nothing happens and cellforrowatindexpath isn't called.
econdviewcontroller:
//I insert data in database and I instanciate class where my tableview is and call refresh method
first = [[FirstviewController alloc]initWithNibName:#"FirstviewController" bundle:nil];
[first refreshList];
in Firstviewcontroller
-(void)refreshList{
self.tableview= [[[UITableView alloc] initWithFrame:self.view.bounds] autorelease];
tableview.dataSource = self;
tableview.delegate = self;
NSMutableArray *array = [[NSMutableArray alloc] init];
//I recover my data from data base
IPADAGRIONEActivityList *arrayActivities = [IPADAGRIONEActivity findAll];
if ([arrayActivities length] > 0)
{
for (IPADAGRIONEActivity * oneRec in arrayActivities)
{
[array addObject:oneRec];
}
}
//activities is NSMutablearray that contains all my data
self.activities = array;
//I build dictionnary
[self buildObjectsDictionnary:activities
NSLog(#"self.act%#",self.tableview);
[array release];
[self.tableview reloadData];
}
//numberofrowsinSection:
NSLog(#"rows%d",[[objects objectForKey:[objectsIndex objectAtIndex:section]] count]);
return [[objects objectForKey:[objectsIndex objectAtIndex:section]] ;
//numberOfSection:
NSLog(#"nbre of section%d",[objectsIndex count]);
return [objectsIndex count];}
//CellforRowatInddexPath: It dosen't access to this method
if (cell== nil) {
cell = [[MHCActivityListCell alloc]init];
}
IPADAGRIONEActivity *activite;
cell.activityCategory.text = [NSString stringWithFormat:#"%#", [activite EMAIL]];
You are instantiating a new tableview every time you call -refreshList. Remember that the tableView is a view, thus it needs to be added as a subview.
Once you understand that, you'll see that there is no reason to alloc+init a new instance of tableView every time you need it to refresh (and if, for any reason you need it, you need to add the tableView as a subview again). Basically, you need to make sure that the tableView that is being displayed is the same tableView that you're storing on your tableView property.
As mentioned earlier by Bruno, you are instantiating your tableview every time and this is not the right approach. You need to refresh the same tableview which had the original data.
in your refresh list do something like this
-(void) refreshList
{
// Get a reference to your viewcontroller's tableview
UITableview *tableview = [self tableview];
// Do your data manipulation
[tableview reloadData];
}