CellForRowAtIndexPath method not being called in storyboards - ios5

I am using storyboards for my app.In that I have a UITableViewController class.I am loading the UITableView from the data coming from the webservice. The issue is that the data is coming but is not geting populated in UITableView. On Decoding I found out that the cellForRowAtIndexPath method is not getting called.
Do we need to connect the datasource and delegate in storyboard as it was done in separate xibs before storyboard. And if so, where to connect the datasource and delegate methods as there is NO Filesowner in storyboard.
I am stuck up with this issue and any help would be appreciated.
Thanks

If you put a table view controller into a storyboard, it usually has the table view's dataSource and delegate already set up correctly. If yours turn out to be connected OK, the other possibility is that tableView:numberOfRowsInSection: is returning zero.

If you are using the UITableViewController, then you need to make the numberOfSections:tableView: data source method returns 1 instead of the default return of 0.
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1 // Default is 0, should be greater than 0
}

Related

When does heightForHeaderInSection gets called

I am calling the following function to update the tableView. However, I am finding that heightForHeaderInSection gets called twice for each section there are in the table. So if I have 5 sections, the function gets called 10 times. Is that normal?
tableView.beginUpdates()
let sections = NSIndexSet(index:posts.count - 1)
tableView.insertSections(sections, withRowAnimation: .None)
tableView.endUpdates()
To answer youre question lets look at UITableViewDelegate. From Apple documentation :
The delegate of a UITableView object must adopt the
UITableViewDelegate protocol. Optional methods of the protocol allow
the delegate to manage selections, configure section headings and
footers, help to delete and reorder cells, and perform other actions.
So when UITableViewDelegate is get called in your'e case? Delegate is get called when you update tableView with insertSections. So heightForHeaderInSection is called after you insert new sections to tableView.
Amount of times that heightForHeaderInSection is get called depends on how you update tableView.
Also it is possible to highlight that Apple do not gives clear explanation how often UIKit would call you're delegate methods.

iOS - UITableView delegate not being set?

The UITableView object I have in my storyboard theoretically should have its delegate set, but it does not. I dragged the UITableView object from storyboard into the header and added it as an IBOutlet property and synthesized it. However, I checked and only the data source method is being called. So something seems to be wrong with the way I'm implementing the main delegate protocol. As you can see in the images below, I seem to be doing everything standardly? But the delegate is not being set still! Thoughts?
I think the reason your solution is not working is because you are using a TableView inside of a UiViewController instead of a UiTableViewController. I had this same issue a while back. Here is what I did. Create an IBOutlet to the header file and synthesize it in the implementation file (I believe you have already completed this step). Go back to the storyboard. control + click on your table view and drag the connector to the view controller (the yellow circle with the white box). Select datasource. Repeat this step again and instead of selecting datasource select delegate. In the menu on the right-hand side you should be able to see your outlets if it is set up correctly. This should fix your delegate problems.
See the screenshot from my example below:
Try changing your numberOfRows method (for better debugging).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rows = [allParties count];
NSLog(#"number of rows: %d", rows);
return rows;
}
If you're returning 0, it won't work.
Also in the future, please paste your code instead of taking screen shots.
You have put a log in both numberOfRowsInSection: which is being called but not the one in cellForRowAtIndexPath: which shows that no cells are being created for your table. You simply are returning 0 as number of rows for the table. Check for that.
And the delegate method didSelectRowAtIndexPath: will be called when you select a row, but for that, you have to have a row first in your table.

Best approach to add Static-TableView-Cells to a UIViewcontroller?

I want to add a tableview-look-a-like-login to my app, but it seems to be not that easy to implement. I tried to accomplish my goal using more then one approach, but i am not sure about which solution is the best.
For example, Dropbox and Facebook have a login page like this.
Here are my 3 approaches :
I added 2 UITextfields to my View (no border) and placed a . png behind, which looks like a tableviewcell. ( Not the best approach cause i want to use real tableviews )
I added a Container View to my ViewController placed a tableview with static Table Views inside. The Problem here is, that i dont know how to access the information inside my viewcontroller?
I added a tableview to my ViewController and used dynamic cells with it. Connected the outlets for delegate and datasource to my viewcontroller and initialized them with the delegate and datasource methods. The Problem here is, that i can not use static table views inside a uiviewcontroller.
Is there any better way of solving this problem ?
I would really like to know how to do this in a more elegant way.
EDIT:
A ContainerViewController basically solved this issue for me some month ago.
After embedding one into the main controller you can access it through the prepareForSegue function and define a protocol-based interface for that specific controller to interact with the embedded controller.
If you want to use static cells inside a regular UIViewController, just add the static cells and design them the way you like in interface builder, then connect the table cells as strong IB outlets (weak won't work, make sure they are strongly referenced). This will work flawlessly if you have a few table cells. Then set the view controller as the data source of the tablet view, implement -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section to return the number of cells and implement -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to return your strongly referenced cell instance for the specified index path. I've used this method for a simple table view in my view controller that had four cells and it is working perfectly. For a large-dynamic data set, I definitely do not recommend this approach but for small, static tables, this does the job right.
I have an idea how to solve this. I think it's a clean way to do so. You do not need storyboard for this controller.
Make your controller subclass UITableViewController like so:
#interface YourViewController : UITableViewController
Then in your viewDidLoad you create the instances of the cells:
- (void) viewDidLoad {
usernameCell = [YourTextFieldCell new];
passwordCell = [YourTextFieldCell new];
}
The YourTextFieldCell is of course your own subclass of a UITableViewCell, which could be something like this:
#implementation YourTextFieldCell {
UITextField textField;
}
- (id) init {
self = [super init];
if (self) {
// Adjust the text's frame field to your liking
textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
[self addSubview:textField];
}
}
// A getter method to access the textfield from the outside
- (UITextField *) textField {
return textField;
}
#end
Back in YourViewController:
- (NSInteger) tableView:(UITableView *) tv numberOfRowsInSection:(NSInteger) section {
return 2;
}
- (UITableViewCell *) tableView:(UITableView *) tv cellForRowAtIndexPath:(NSIndexPath *) indexPath {
if (indexPath.row == 0) {
return usernameCell;
} else if (indexPath.row == 1) {
return passwordCell;
}
return nil;
}
Do you get where I am going with this? This is how I think you should do it! Good luck!
I think your approach 2 is the best. If you need to access information in the table view controller, from your UIViewController (which will be the parent view controller), you can get a reference to that table view controller with self.childViewControllers.lastObject. In the viewDidLoad method of the UIViewController subclass, you could set yourself as the delegate of the table view with this line if you want:
[[(UITableViewController *)self.childViewControllers.lastObject tableView] setDelegate:self];
That way, you could implement the tableView:didSelectRowAtIndexPath: method in the view controller, which will get the information I'm guessing you need.
If you go with your option 2) using a storyboard and have a ContainerView containing your own subclass of UITableViewController with static cells then you can implement the prepareForSegue: method in your parent ViewController to take a reference to the UITableViewController (it'll be the destinationController of the segue) and also to pass itself down to the UITableViewController subclass if necessary (which should hold onto it with a weak reference).
Disclaimer - This answer will work for any size of UITableView, but if you're just making a login view, Tom's answer will work quite well.
I'm not sure if this will help, but what I did for this was create my own UITableView-esque subclass with a UITableViewCell-esque subclass as well.
This may not be what you want to hear, but I find what I made to be really helpful, since I've used it a number of times now. Basically, you have a UIView with the stylistic approach for the different types (10.0f - 20.0f cornerRadius and a 1px border (divide by UIScreen's scale property for retina). As for the cell, you'll want to have a full sized UIButton on it that responds to your table view for the touch events either with a delegate or by setting the target and tag inside your table view's class.
Last, you'll have a delegate system just like the UITableView for your information for building the specific tables.
In short, you'll need:
2 UIView subclasses (TableView and TableViewCell)
2 Delegates/Protocols (TableViewDataSource and TableViewDelegate)
Optionally
1 Delegate (TableViewCellResponseDelegate)
1 NSObject Subclass (Contains all of the information needed in each cell - Ease of use)
I found Can's solution to be the best / easiest, but unfortunately it breaks in XCode 5.1 --
I found a workaround which builds off the same basic idea, but unfortunately requires a little more involvement: http://www.codebestowed.com/ios-static-tableview-in-uiviewcontroller/
To summarize, you can add TableViewCells directly to views (and create IBOutlets from them, etc), but in order for them to get "moved" to the TableView properly, you need to remove them from the view in code, and you also need to set Auto-Layout constraints in IB.

How to stop UITableView from loading until data has been fetched?

I understand that UITableView will call -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method to get each of the cells for the table view. Say I have my data source is fetched over the internet and I have to account for latency. What will be the best way of "stopping" this method from being called? Should it block on a boolean flag in the application? Should I just call cellForRowAtIndexPath again from within my application?
I am uncertain as to when the function gets called, ie, how often the UITableView "refreshes" itself. Any explanations will be helpful! Thanks!
If you don't have data, or you don't have the data for additional cells, then cellForRowAtIndex: will not be called as long as you don't tell the UTableView that you have rowCounts or new rowCounts. That value is being set in numberOfRowsInSection:.
In other words, don't report any new cells in numberOfRowsInSection:, until you actually have that data in hand, and then cellForRowAtIndexPath: won't be called prematurely.
When you do get the additional row data, then call reloadData to get the UITableView to ask for the number of rows and then call cellForRowAtIndex:.
If you've set UITableView datasource and delegate from IB then it will at least go for numberOfRowsInSection method when you push to the view, however if you're showing data from an NSArray, it'll return count ZERO if array is still empty, so table won't go for other methods to call.
In practice, I'm pulling data from web service to feed the table, so I am not setting up the datasource and delegate from IB instead once I get the data and status OK response I'd set the tableview.datasource = self and tableview.delegate = self and then call reloadData method to update table. This ensures that it won't go for numberOfRowsInSection method as you don't need to call it up without having the data.
What you should do is call reloadData on your table view when your data is done being fetched. That will force the table view to call it's delegate methods again for display. Those methods are called whenever the table view needs to re-display, so either when it comes into view, scrolling occurs, or you manually call reloadData.
When you invoke [tableView reloadData], the framework automatically invokes all the data source methods again for the table view cells that are visible currently (not for all the cells of the tableview). So the best approach would be to invoke reloadData every time you get data from the internet.

UITableView and didSelectRowAtIndexPath issue

I have a UITableView populated with a location-based datasource. I'm calling [self updateView]; to manually refresh the view after the location is found which works fine...but for some reason the didSelectRowAtIndexPath method isn't getting called. Any ideas of why it's not working?
Code snippet: http://pastie.org/464300
Ensure that the delegate property of your tableView is set.
slf said:
Make sure it's defined in your .h
file. The protocol does a
'doesRespondToSelector' first and if
you aren't making it public through
your header the message my fail
-respondsToSelector: will detect methods that are not exposed in the interface.