I am addicted to use TableViewController in storyboard whose class directly inherits from UITableViewController and functions like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
are there by default and you just have to implement them. But now I am using a ViewController (inherits from UIViewController) in storyboard and using a UITableView control from Object library into the view controller by drag and drop. Obviously the class I would attach to my storyboard ViewController will be inherited from UIViewController. Now how do I interact with the table cells in the UITableView control in my view controller. Want to implement same row functions above.
Implement UITableViewDataSource and UITableViewDelegate protocols in your view controller .h file.
Have an outlet for the UITableView.
In viewDidLoad, set the tableView's datasource and delegate to self since the viewcontroller implements the protocol.
Then, write the cellForRowAtIndexPath method. It will be getting called.
You have to assign UITableViewDelegate and UITableViewDatasource protocols to your table and implement it. Methods in your question are methods from these protocols and they appears automatically when you use UITableViewController.
Related
I am developing an iOS app which has a TableView, and I want to do sth that when a cell of the TableView is tapped, a new view opens (and then it can get back to the Table View.) I tried some things like working with segues and new view controllers, but it didn't work.
Implement the UITableViewDelegate Protocol :
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
For this Protocol the delegate method is below:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Create Object for next view controller
NextViewController *vc=[storyboard instantiateViewControllerWithIdentifier:"NextViewController"];
[self.navigationController pushViewController:vc animated:YES];
}
}
Implement the UITableViewDelegate protocol, and implement the method
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Inside that method you can create your new view.
All the guidelines suggest adjusting the Top Layout Guide to avoid clobbering the status bar. But, if the page is created with a View Controller other than UIViewController (for example, if it is created with UITableViewController because the page is mainly a table view) then it has no layout guides. How can I then avoid the status bar?
I've found the UITableViewController to be more trouble than it's worth, like this guy: How do I make my iOS7 UITableViewController NOT appear under the top status bar?
Now when I implement a table view I find it easier to make the TableView a property of the UIViewController, then you set the delegate and the datasource responsibilities to the UIViewController. From there you can customize it however you want really. You can play with the Storyboard options like the Status Bar setting (Inferred, None, Black etc) but in my experience I have found it works best by just putting a UITableView inside a UIViewController.
Example Header:
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
Example Code in Controller
#synthesize myTableView;
//**** Table View Delegate and Data Source ****//
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *myCellIdentifier = #"myCell";
MyTableViewCell *cell = (MyTableViewCell *)[myTableView dequeueReusableCellWithIdentifier:myCellIdentifier];
//Customize the cell
return cell;
}
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [myDataSource count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//perform some action on click
}
Another example of UITableViewController without a NavigationController and problems with the status bar: iOS 7: UITableView shows under status bar
An UITableViewController (and all other standard view controllers) inherit from UIViewController, so they have all the properties and methods of UIViewController, including top and bottom layout guides, which you can definitely use.
Since UITableViewController is inherited from UIViewController, then in Tableviewcontroller, you can override this method
- (UIStatusBarStyle)preferredStatusBarStyle {
if(<#condition>)
{
return UIStatusBarStyleLightContent;
}
else
{
return UIStatusBarStyleDefault;
}
}
If you must use UITableViewController you can embed it inside a UIViewController with an Embed Segue and do whatever you want in the UIViewController
I have a slide menu. It is implemented using component SWRevealViewController. To implement it I have 1 main UIViewController (VC) - SWRevealViewController. I have menu VC and I have push segues to navigate to different menu's VCs.
For the menu I use prototype cells with custom class for each menu.
My problem is that I need to call unwind segue to go to login VC, using alert view. To do that I try usual method [self performSegueWithIdentifier:#"unwSegReturnToLogin" sender:self]; on positive answer from the alert view (inside custom class for exit cell). I have such method declared in my login VC. I receive error during the compilation:
No visible #interface for 'tvcellExitMenuItem' declares
the selector 'performSegueWithIdentifier:sender:'
I suspect that the problem is that self in my case is table cell and that is not UIViewController.
How to refer parent VC if this is the case?
If not, please tell me where I am wrong in the logic.
A subview shouldn't have to know about its parent viewController. Instead, a common pattern that fits your need is the delegate pattern : define a delegate property & protocol for your cells' class.
// your cell class header might look like this
#class MyCellClass;
#protocol MyCellDelegate
- (void)onCellSelected:(MyCellClass *)cell;
#end
#interface MyCellClass
#property (nonatomic, weak) id<MyCellDelegate> delegate;
#end
For example, if your viewController is also your UITableViewDatasource , then in tableView:cellForRowAtIndexPath: you can set your cell's delegate to self, and call the segue methods in delegate method.
- (void)onCellSelected:(MyCellClass *)cell
{
// retrieve cell indexPath
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
// using indexPth, retrieve cell's data
// push segue with data selected
}
Of course, this is only an example, and there are other corrects ways to do that.
I couldn't find an example with good explanation how to include UITableView in my project using MVC pattern.
Let's say that at the beginning I have only two files 'MainViewController' (:UIViewController), and 'MainModel' (:NSObject) containing my Array with data for cells.
Where I should have a reference to UITableView object, which file should be delegate for table, ... ?
Your MainViewController will have a view property that you should point to your UITableView instance. You can have any object be your delegate, but usually your delegate is the view controller that controls it, which would be your MainViewController.
That said, there's a subclass of UIViewController called UITableViewController that you should probably be using as the superclass of MainViewController. It has some automatic functionality for controlling UITableViews. In fact, instantiating a UITableViewController (or any its subclasses) will automatically create a UITableView and point to it in its view & tableView properties.
So your MainModel is the model. MainViewController is your controller. The tableView is your view. Add it as a property to your MainViewController and set your MainViewController to be the dataSource and delegate for the tableView. Then when you are populating the tableView, use the data in your MainModel. For instance:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[MainModel sharedInstance] myArray].count;
}
Or create an NSArray property on MainViewController and populate it from MainModel in viewDidLoad or viewWillAppear.
When I work with a TableViewController I am able to setup all my content in storyboards. Since I use Static Cells instead of Dynamic Properties for my table view, I find this method much more convenient and easier to implement. I hook up the new UITableView class and simply delete all the delegate methods. Works like a charm as ALL of the content / buttons are being setup in storyboards.
I am trying to accomplish the same result, except this time, I have to work within a ViewController and add a TableView as a subview. Once I hook up the right class, add my outlet connection and setup the following delegates:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MainCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
This works well if my TableView is set to Dynamic Properties :
But when I change the Table View content to Static Cells and delete the delegate method, my app crashes. So, How can I add a table view with Static Cells (That I can manipulate in storyboards) to my ViewController?
Here is what you can do. In your storyboard, create a parent view controller that contains all your non tableview views also, create a UITableViewController. In your parent view controller, create container view, delete the view controller it auto adds, and right click and drag from the container view to your UITableViewController to create an embed segue. Your end result should look something like this:
As far as I know, you can't do this directly. At least in iOS 6, you had to use a UITableViewController when using static cells. One way to use a static table view inside a UIViewController would be to add a container view in IB, and make the embedded controller a table view controller (delete the UIViewController you get automatically, drag in a UITableViewController, and hook it up with the embed segue). You can get a reference to this table view controller from the UIViewController by implementing prepareForSegue:sender:, and using the destinationViewController property (which will point to the table view controller).
You still need to do a couple of things:
Add <UITableViewDataSource, UITableViewDelegate> to your #interface declaration.
Then you can set these also in Interface Builder.
Implement cellForRowAtIndexPath and call the dequeueReusableCellWithIdentifier method to return the cell.
Sorry, I was wrong. The truth is you cannot use static cells without a UITableViewController. Sorry.
A solution could be that you create two controllers and just add the view of the table view controller to your other view controller.