reloadData not triggering cellForRowAtIndexPath - objective-c

I have a UIViewController with one UITableView in it. The table view holds a list of favorites that can be changed by other parts of the app. I am using NSNotificationCenter to trigger the table view's reloadData method. The table view has an outlet declared as follows:
#property (strong,nonatomic) IBOutlet UITableView *faveTableView;
and synthesized as follows:
#synthesize faveTableView;
The delegate and datasource properties of the table view are set in the view controller's viewDidLoad as follows:
[self.faveTableView setDataSource:self];
[self.faveTableView setDelegate:self];
The NSNotificationCenter causes the following method to fire:
-(void)reloadNotificationReceived{
[self loadData];
[self.faveTableView reloadData];
}
loadData updates the data source which is NSMutableArray of managed objects and is working as it should.
When the view controller loads, cellForRowAtIndexPath is fired as it should be. However, when the notification is received, reloadNotificationReceived is fired and two of the table view delegate methods (numberOfRowsInSection and numberOfSectionsInTableView) ARE fired. However, cellForRowAtIndexPath is NOT fired. numberOfRowsInSection IS returning the correct number of items.
Can anyone offer up a reason why cellForRowAtIndexPath does not get fired here? Thanks!

The number of rows you are returning is 0.

Perhaps you have set the delegate/datasource of the tableview to your controller in the storyboard/xib, but you haven't wired up the "faveTableView" tableview IBOutlet of the the controller... If the del/datasource are set, then the it will successfully get data from the controller, but without the IBOutlet being set, the self.faveTableView will remain nil and hence [self.faveTableView reloadData] won't do anything. Put a breakpoint in your viewDidLoad and check whether the self.faveTableView is not nil...

Related

Accessing a view controller's delegate from a Category on that view controller

I've created a Category on UITableViewController and was wondering if it's possible to access the tableViewController's delegate, i.e. can I put something like this into my Category?
UIView *firstHeader = [self.delegate tableView:self.tableView viewForHeaderInSection:0];
Obviously, the above doesn't work, but is there something along those lines I can use?
The delegate is on the tableView, not the tableViewController, hence the following is what's needed:
UIView *firstHeader = [self.tableView.delegate tableView:self.tableView viewForHeaderInSection:0];

Calling reloadData on same UITableView, but it seems like it's calling on a different one

This has been a headache for few hours now and I finally found out what is actually happening, but I don't know how to solve this issue.
I've got List.h with UITableView properly connected from storyboard:
#property (strong, nonatomic) IBOutlet UITableView *tableView;
Then there's List.m where I set delegates and datasource for my UITableView:
// Set tableview datasource and register class for cell reuse
self.tableView.dataSource = self;
[self.tableView registerClass:[TableViewCell class] forCellReuseIdentifier:#"cell"];
// Set tableview delegate
self.tableView.delegate = self;
// Set tableview cells style
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = [UIColor colorWithWhite:0.1f alpha:1.0f];
// Set tableview frame
self.tableView.frame = CGRectMake(0.0, 35.0, self.tableView.frame.size.width, self.tableView.frame.size.height-35.0);
Then on NSNotification I'm trying to [self.tableView reloadData]:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doUpdateAppBefore:) name:UIApplicationWillEnterForegroundNotification object:nil];
Also I'm reloading data of tableView on every UIApplicationBecomeActive notification.
Before I close my app and open it up from background to find out if it's reloads the data, I'm moving to another UIViewController and going back, which causes that somehow identifier of my self.tableView changes. I'm checking it in:
NSLog(#"Calling reloadData on : %#");
and at the beginning it gives me:
Calling reloadData on <UITableView: 0x9b09400;....
but after I segue back from another UIViewController it gives me:
Calling reloadData on <UITableView: 0x9b4b000;
which causes that it doesn't actually reload the data after I open up the app from the background state.
I've been thinking... when I segue back from another viewcontroller, viewDidLoad fires again, is it possible that it somehow sets tableView.delegate again and changes something? Just thinking...
Thank you very much for your answers.
It sounds like you have a view controller, push a modal view on top of it, and then want to go back to the original view controller when you're done. So, you set up a modal segue in your storyboard, and then a second modal segue to go back. The problem is that your second modal segue doesn't return to the original view controller, but it creates a new instance of that view controller, and now your have the original view controller, the second view controller, and an unwanted third view controller. Instead of creating a segue, which creates the third view controller, you need to dismiss the second view controller, which then gets you back to your original view controller, and therefore also your original table view. So what you want to do is get rid of the second segue and replace it with an IBAction, put something like
- (IBAction)goBack:(id)sender;
in your .h file. Connect that to your button or whatever you're using to trigger the segue now. Then, in your implementation file, dismiss the modal view like so:
- (IBAction)goBack:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
That should get you what you want.
Alternately, and this is probably better, you can use an unwind segue as well. Go to List.h, and create this method:
- (IBAction)unwind:(UIStoryboardSegue *)segue;
Then just implement it, you can leave it blank for now. Then, drag from the button that currently triggers the segue to Exit, and select the Action Segue unwind. That will also get you back.

How to make viewWillAppear to be called when we use a subclass of UITableViewController to handle table delegate?

I want to make my code more modular and flexible.
So rather than setting a the tableViewDelegate as the UIViewController, I have a subclass of UITableViewController as the tableView data source and delegate.
Basically, the original UIViewController provides the view for the subclass of UITableViewController.
That way similar tables can be used by several UIViewController's subclasses.
In some cases, UIViewController's provide the tableView and I just switch the tableView delegate at run time.
Works well.
Here is the code for BGTableViewDelegateMother that inherits from UITableViewController (that inherits from UIViewController.
#implementation BGTableViewDelegateMother
-(void) setDelegate:(id<BGTableViewDelegateMother>)delegate
{
_delegate=delegate;
self.view = self.delegate.tvDelegated; //So that viewWillAppear would work fine
[self view]; //load the view view didload is not called either
self.delegate.tvDelegated.delegate =self;
self.delegate.tvDelegated.dataSource=self;
}
Okay. The UITableViewController.view is used for one thing. Now that it points to the correct tableView, I expect viewWillAppear to be called. It's not
I think everytime the tableView will be shown, I should at least reloadData
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];//never called
[self.delegate.tvDelegated reloadData];
}
This code never called. Even though the view will indeed appear. Why?
viewDidLoad is also never called.
Make the table view controller a child view controller of your view controller while its view is linked (and it is the data source) and could be on screen. This tells the view controller hierarchy that the table view needs to know about the appearance callbacks.

UIView subclass dealloc not called

I am using AQGridView for displaying a grid of images in my app. A user clicks on an album and then I open a new controller with the grid that has all the images. The problem is that the when the user presses the back button to go back to the list of albums, the dealloc on the grid view is not getting called. I have logged a string in dealloc of my view controller and it is being called.
I have checked the heapshots in Instruments and everything related to AQGridView is not deallocated even after the view is popped. I use Interface Builder to create the grid view and it is connected to grid view in my .h file.
#property (weak, nonatomic) IBOutlet AQGridView *gridView;
I am not holding any other pointers to the grid view. I am using ARC for the project. Do I need to deallocate the gridView somehow in the grid view controller's dealloc or is it handled automatically by ARC? If it is, what might be preventing it from being deallocated?
EDIT:
I am using NSOperationQueue to load the images in the background and then after the images are loaded, I put them in grid cells.
In the dealloc method of your grid view controller, set the gridView pointer to nil.
-(void)dealloc
{
self.gridView = nil;
}

presentModalViewController on Parent from UITableView inside UIViewController

This one is probably something simple, still learning the ins-and-outs on this but I've run out of searches for this one with no available answer.
I've got a UIViewController with several elements displayed on it, one such element is a UITableView. The UITableView has it's own class and is allocated in the UIViewControllers viewWillAppear
- (void)viewWillAppear:(BOOL)animated
{
UITableView *insideTableView = [[UITableView alloc] init];
tableView.delegate = insideTableView;
tableView.dataSource = insideTableView;
}
Everything is working fine in regards to the tableview. Today I am experimenting with a few additions, one of which is a new view popup on cell selection within that tableview.
Inside my TableView Class, I have the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Cell Pressed, Present View");
PopupView *popupView = [[PopupView alloc] initWithNibName:#"PopupView" bundle:nil];
popupView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:popupView animated:YES];
}
Now it gets called fine, verified by the NSLog, however the view doesn't appear. I know the problem is related to the fact that I want PopUp to appear over the TableViews Parent rather than itself.
I'm just not sure how to properly call it in this instance.
The delegate is a UIViewController which doesn't have its view property set, which is why presentModalViewController:: doesn't work.
You need the view controller containing the table view to present the modal view controllers, but note that that view controller is not the parent of the table view delegate. This is because you have no view controller hierarchy in place.
The easiest way to fix this is to put those methods inside the view controller whose view contains the table view. Alternatively the table view delegate needs to hold a reference to the view controller so it can call presentModalViewController:: on it.
The latter approach can lead to retain cycle, so you have to use a non-retaining reference. The nicest implementation is the delegate pattern.
Also, you don't want to do the instantiation in viewWillAppear: because that can be called multiple times during the lifecycle of a view controller. Put the code in viewDidLoad and balance it in dealloc. Right now you are leaking memory every time your view appears, which when your modal view controller is working will be every time the modal view controller is presented and dismissed.