1
votes

I need to display UITableViewController programmatically from existing view.

I have a MyAppViewController and the button on its view should open a new UITableViewController. But I cannot seem to get it working so far. Here is how UITableViewController looks like:

@interface SecondViewController : UITableViewController{}

and on the main view I add table view controller using the following:

SecondViewController vc2 = [[SecondViewController alloc] init];
vc2.view.frame = {...}
[self.view addSubview: vc2.view];

This is how I would normally add a simple view controller so I thought UITableViewController is the same.

The result I get is empty cells on the entire screen. This is because of the delegate not set, I assume, but where would I set it? So my confusion is the delegate setters on UITableViewController view controller and displaying UITableViewController correctly from the main view controller's view.

4
A bit confused, you are asking how to add a UITableViewController or how to set the cell's content for the UITableView?Steven
how to add a UITableViewController... if I do it successfully I think I will be able to take care of cell contentVad
@Vad: are you using storyboards?GeneralMike
No, I'd like to make it happen programmatically if possibleVad
@Vad: you can still do it programmatically even it if it in a storyboard. I ask because the syntax will be a little different if they are views on a storyboard vs if you have .nib vs if the controller is set up completely programmatically.GeneralMike

4 Answers

4
votes

EDIT

This answer is outdated. The correct way to add a view controller's view as a subview of another view controller is to implement a container view controller.

https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html

ORIGINAL ANSWER

Your pattern is a bit out of the ordinary. The most common way to do what you are describing is to initialize and present SecondViewController. If that's in fact what you want I highly recommend you peruse Apple's docs on how to create, customize, and present UIViewController and UITableViewController.

If you know all of that and really want to do something custom then read on.

Instead you are creating an instance of SecondViewController and rather than presenting it, you are adding it's view to the current view controllers view. If you know what you're trying to accomplish and this is in fact your desired result then go for it.

There is more than one way to configure this general pattern. I'll stick to the simplest way in this example.

1) MainViewController (MVC) should retain the SecondViewController (SVC) instance in a property as long as it is needed.

2) SVC is a subclass of UITableViewController so by default, it is set as the dataSource and delegate for it's UITableView. That means you need to implement the UITableViewDataSource and UITableViewDelegate methods in SVC for your table to be populated with data. Assuming MVC knows what data needs to go into the table, it should pass this to SVC. The simplest way is to define a property on SVC that can be set in MVC at initialization time.

3) Assuming there is a way to dismiss the table after it has been presented, you'll want MVC to do that. Basically, MVC would remove SVC's view from it's superview and then set the SVC property to nil.

Here's some quick psuedo-code. I wrote the bare minimum as an example.

// MainViewController.h
//
#import "SecondViewController.h"

@interface MainViewController : UIViewController
@property (nonatomic, strong) SecondViewController *svc;
@end

// MainViewController.m
//
#import "MainViewController.h"

@implementation MainViewController

// init and configure views w/ init, loadView, viewDidLoad, etc

// present SecondViewController
- (void)presentSecondViewController:(id)sender {
    self.svc = [[SecondViewController alloc] init];
    // this example uses an array as the SVC data
    self.svc.tableData = @[@"first", @"second", @"third", @"fourth"];
    self.svc.view.frame = self.view.bounds;
    [self.view addSubview:self.svc.view];
}

// dismiss SecondViewController
- (void)dismissSecondViewController:(id)sender {
    if (self.svc) {
        [self.svc.view removeFromSuperview];
        self.svc = nil;
    }
}

// SecondViewController.h
//
@interface SecondViewController : UITableViewController
@property (nonatomic, strong) NSArray *tableData;
@end

// SecondViewController.m
//
@implementation SecondViewController

// init and configure views w/ init, loadView, viewDidLoad, etc

// override tableData getter to create empty array if nil
- (NSArray *)tableData
{
    if (!tableData) {
        _tableData = @[];
    }
    return _tableData;
}

// override tableData setter to reload tableView
- (void)setTableData:(NSArray *)tableData
{
    _tableData = tableData;
    [self.tableView reloadData];
}

// implement UITableViewDelegate and UITableViewDataSource methods using
// the self.tableData array
0
votes

In your header you'll have to tell your view controller to conform to UITableViewDataSource and UITableViewDelegate. Add this right after "UIViewController"

<UITableViewDataSource, UITableViewDelegate>

Then in your implementation file you'll need to add the delegate and data source methods for the table like:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

And

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

You can find a full list in the UITableViewDataSource and UITableViewDelegate class references.

Additionally, where you alloc init your table view you'll need to set it's delegate and datasource to the current class:

[myTableView setDelegate:self];
[myTableView setDataSource:self];
0
votes

Okay, first off I think what you are doing with [self.view addSubview] is piling all the views in your project into the same view controller, where the more traditional way to do it is to dismiss a view controller when you are done with it and create the new view controller on it's own. The piling up you are doing is unconventional, and I think it will be misleading to whoever tries to look at your code in the future. Additionally, it's going to be a headache if you actually start trying to do standard navigation. Also, it looks like a memory management nightmare (although I admit I'm still a little fuzzy on that, so I don't know if ARC would clean it up for you or not, if you are actually using ARC). That said, there are cases where you might be trying to do that - but if you're not sure, that means it isn't what you want to be doing (if it is what you want to do, check out XJones' answer). What I think you're looking for is presentViewController - that is the more conventional way to get rid of an unneeded controller and replace it with a new one. Get rid of

vc2.view.frame = {...}
[self.view addSubview: vc2.view];

and replace it with

[self presentViewController:vc2 animated:/*YES or NO, try them both and use whichever one you like better*/ completion:NULL];

NOTE: I'm not entirely sure what completion does (I think it maybe allows you to run an extra method once vc2 is built - there are some examples if you google "presentViewController examples" that you could take a look at to get more information, or check the Apple Docs). I do know that keeping it NULL will work, and probably do what you need.

Once you do all this, you will be right back to where you are now, where you will have a view with a bunch of empty cells on it (but you will have gotten there in a more conventional way).

From here, you need to add some code to your SecondViewController.m to tell it what you want to show. Generally, you'll have an array of strings and you want the 1st cell of your table to have a label that displays 1st string in that array, 2nd cell shows 2nd string, and so on. To do this, you'll have something like cell.textLabel = [myArray objectAtIndex:indexPath.row];.

There is a lot more to setting up a UITableViewController than I could get into in this post, so check out some tutorials on YouTube or something, as they have already taken the time to explain everything you need in a much more digestible format (I found this one to be very helpful when I was first starting using table views, but there are tons of others there too).

0
votes

Here is The Code

1)Add DataSource and Delegate .h

2)Create SOme Code in .m

   thisTableView = [[UITableView alloc] initWithFrame:CGRectMake(6.5, 60,      self.view.bounds.size.width - 10, 350) style:UITableViewStylePlain];

    [thisTableView setBounces:NO];
    thisTableView.backgroundColor = [UIColor whiteColor];

thisTableView.delegate = self;
thisTableView.dataSource = self;
[self.view addSubview:thisTableView];
    [thisTableView release];