How delegation work if UITableViewController added to other UIView? - ios

I want to present a UITableViewController in a UIView, I have a workaround, but I want to understand why it works this way.
This is how the scenario looks like:
- Created a new Single View Application
- In IB added a view to the main view
- Created an outlet for the view:
#property (weak, nonatomic) IBOutlet UIView *placeholderView;
- Added a new UITableViewController with XIB to the project
- Changed numberOfSectionsInTableView to return 1, numberOfRowsInSection to return 10, and cellForRowAtIndexPath:
cell.textLabel.text = #"hello";
- In ViewController file ViewDidLoad method:
ORGTableViewController *tableView = [[ORGTableViewController alloc] initWithNibName:#"ORGTableViewController" bundle:nil];
[self.placeholderView addSubview:tableView.tableView];
Now the table appears in placeholderView but, it's empty. In TableViewController file InitWithStyle, and ViewDidLoad methods are called. But none of numberOfSectionsInTableView, numberOfRowsInSection, and cellForRowAtIndexPath are called.
Also tried to add this code in AppDelegate to didFinishLaunchingWithOptions method, and it's —working as expected, cells with text are appear:
ORGTableViewController *tableViewController = [[ORGTableViewController alloc] initWithNibName:#"ORGTableViewController" bundle:nil];
self.window.rootViewController = tableViewController;
So it works, and it looks like delegation messed up somehow as I added UITableViewController to UIView, workaround is easy... ViewController, viewDidLoad method:
ORGTableViewController *tableViewController = [[ORGTableViewController alloc] initWithNibName:#"ORGTableViewController" bundle:nil];
tableViewController.tableView.delegate = tableViewController;
[self.placeholderView addSubview:tableViewController.tableView];
Do you know why delegation work this way?
THX!

Your question itself has the answer. In the first code, you were not setting the deletage where as in your second code, you are setting the delegate as tableViewController.tableView.delegate = tableViewController; which will call the delegate methods implemented in tableViewController.
If you are planning to implement delegate methods in your placeholderView class, you need to set the delegate as `tableViewController.tableView.delegate = self; and then implement all the delegates in placeholderView class. That would have worked.
If you just need a UITableView, you can also consider subclassing the UITableView class and add it as the subview of placeholderView.

Related

UITableView content is gone

I'm facing a strange behavior of a UITableView. I have a View Controller with a UIView, let's call it view A.
Inside UIView A I'm calling another view from a UIViewController, called view B.
HomeViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UIView *B = [[BViewController alloc]init].view;
[self.A addSubview:B];
}
Inside B, I have a UITableView C.
BViewController.m
- (void) viewDidLoad
{
C.delegate = self;
C.dataSource = self;
[self.view addSubview:C];
}
This UITableView is loading correctly but when I just tap on the screen all of the table's content is gone. Just an empty table remains.
In your view controller B made property of type A and name it to delegate and set it with instance of A and set that delegate property to your table view' datasource and delegate instead of self. Because in viewdidload of B you are setting delegate and data source as self that means instance of B and your table view is being shown on viewcontrollet A. So A's instant would be the delegate of tableview. So set tableview's delegate and datasource to self in vc A or as i mentioned in above lines.Or you should add vc as childviewcontroller.
Following the official documentation of View Containers my problem was solved.

Tableview to another viewcontroller

I have a controller named as "firstViewcontroller" where i have a UITableView named as "discoveredInstanceTableView". I want to load that UITableView in to another UIViewController named as "secondViewcontroller"
I have used the below code but it is not working, It says property "discoveredInstanceTableView" not found ...Anybody please help me:
In the firstViewcontroller:
IBOutlet UITableView *discoveredInstanceTableView;
In the Secondviewcontroller:
firstViewcontroller *vc1 = [[firstViewcontroller alloc]initWithNibName:#"firstViewcontroller" bundle:nil];
[self addChildViewController:vc1];
[self.myTableview addSubview:vc1.discoveredInstanceTableView];
What you asked is valid only if you curious to know why the above thing is not working answer would be
You are doing something that is not allowed, this can not be done as per the documentation.
However, If we forget about the right wrong approach, you probably adding a table view as a subview over a table view itself and I am sure you passing a table view to a table view which might not be allocated.
First think about the UITableView how it works? it simply a ScrollableView which display content over its cells.
Eventually would recommend you read about TableView
EDIT: From the Above Comments
IMPORTANT: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.» As UITableView is a UIScrollView, this applies here as well.
Possible Alternatives of displaying TableView inside the SecondViewController
Use #Rajath Kornaya's Answer And In my opinion that is not right approach since whenever you required callback action like on cell tap, you want to display an alert(or something else), you can't get the delegate callback inside the SecondViewController
But there are so many other right approaches available, that you should follow up.
Create a TableView separately either programmatically or through the XIB/Storyboard
Add delegate and data source (methods which responds when something interesting happened e.g Cell going to populate called cellForRowAtIndexPath) to current SecondViewController
Define all required data source methods and write proper code.
If you required to do something on cell tap, add specific delegate method too.
But if you want to reuse the FirstViewController Class TableView simply create a CustomView and add TableView inside there and simply add that view to each view controller class.
I hope it may helps you!!!
declare in viewcontroller2
#property (nonatomic, strong) UITableView *table;
create table in viewcontroller1
tableView=[[UITableView alloc]initWithFrame:CGRectMake(10, 10, 250, 300) style:UITableViewStylePlain];
[self.view addSubview:tableView];
tableView.backgroundColor=[UIColor greenColor];
while calling viewcontroller2 pass table to viewcontroller2
ViewController2 *v2=[[ViewController2 alloc]init];
v2.table=tableView;
UINavigationController *navigation=[[UINavigationController alloc]initWithRootViewController:v2];
[self presentViewController:navigation animated:YES completion:nil];
in viewcontroller2 access the table using the global variable
[self.view addSubview:self.table];

Segue From Custom UIView which is alertview to UIViewController

I have a button on UIViewController on click of that button an UIview gets poped up like alertview which has tableview in it.Now on selection of table cell i would like to segue to the detail viewcontroller
Here's the link to which i refered but none of them worked for me
For alertview i have used (https://github.com/kwent/ios-custom-alertview)
Thanks.
#yar1vn's answer is right, however, I'll describe more precisely what you need to do.
Custom alert view from your link has a delegate property, which should conform to protocol
#protocol CustomIOS7AlertViewDelegate
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
#end
that means you should implement this method in your UIViewController.
in .h file:
#interface YourViewController : UIViewController <YourViewController>
...
#end
in .m file:
#implementation YourViewController
...
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
and set the delegate when creating alertView:
[alertView setDelegate:self];
#"YourSegue" is the segue from the controller which shows alertView to the detail view controller.
I disagree that you should use UIAlertController, since if your deployment target is iOS 7 (which is reasonable) you should not use new features of iOS 8
EDIT:
if you want to launch segue from tap on table view cell, you should call [self performSegueWithIdentifier:#"YourSegue" sender:nil] from tableView's delegate method -tableView:didSelectRowAtIndexPath:
I assume you have set current view controller as tableView's dataSource and delegate, so add to your view controller
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
EDIT 2:
though setting the UIView as delegate is not the best approach, we can handle it :)
I see two solutions:
the first is to add the controller as the property to your view like this:
#interface YourView : UIView <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) YourViewController *parentController;
...
somewhere (probably, in -viewDidLoad) you set this property as
youViewInstance.parentController = self;
and the in view's delegate method call
[self.parentController performSegueWithIdentifier:#"YouSegue" sender:nil]
the second one is to simply set the controller as tableView's delegate and call performSegue: from its method. And you should describe all details more completely :)
You shouldn't use 3rd party AlertViews anymore. You can use the AlertController provided with iOS 8 SDK.
I don't know how this AlertView works but the readme mentions a delegate. Did you try calling the segue from the delegate method?

UILabel is always nil

I have the following problem.
This is my Code:
GTSearchViewController* vc = [[GTSearchViewController alloc] initWithNibName:#"GTSearchViewController"
bundle:nil];
vc.headlineLabel.text = [[self.categorieArray objectAtIndex:indexPath.row] valueForKey:#"categoryName"];
[AppDelegate().centerViewController pushViewController:vc
animated:YES];
As you can see, I try to push a New ViewController with a xib File and want to set a String in my headlineLabel from my Array self.categorieArray. But when the SearchController gets pushed, everything works perfect, but my headlineLabel is always nil.
I don't understand why, I thought I don´t need to call "alloc-init" in the SearchController because everything is build with Interface Builder?
Your problem is changing UI before it actually is loaded.
You should set label's text in ViewDidLoad of your view controller (it is called after the view is loaded).
Make NSString property in your SearchViewController class and set it right after initialization.
vc.headlineText = [[self.categorieArray objectAtIndex:indexPath.row] valueForKey:#"categoryName"];
Then in SearchViewController you should override viewDidLoad method:
- (void) viewDidLoad{
[super viewDidLoad];
self.headlineLabel.text = self.headlineText;
}
P.S. Of course I assume that you've set headlineLabel outlet correctly (from Interface Builder).

How can I show a new view from the UITableViewController contained my UIViewController?

I have a UITableViewController within a UIViewController. While this table viewcontroller was the only one involved, it was pushing views just fine when the user would tap a row. However, ever since I moved it to be one of two contained within the UIViewController, the taps of rows suddenly do nothing.
I've tried searching around and I'm not the first to run into this problem, but none of the answers fit my circumstances or the questions have no working answers. That link was the closest I found, but I'm not using storyboards -- I'm using separate XIBs.
So how do I push a new view from a viewcontroller within a viewcontroller?
To recap:
Here is what I had, and it worked fine in taking users to a new screen!
// Normal table behavior, as illustrated by [another question][2].
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SomeView *detailViewController = [[SomeView alloc] initWithNibName:#"SomeView" bundle:nil];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
}
Now I have the viewcontroller as a property in a view -- and the above code, which is in the file for the tableviewcontroller and not at the "main" view, doesn't cause a new screen to appear anymore!
Thanks for the comments! Here's some code to clarify my scenario.
The controllers within a controller. This is a file from a test project I've been using to test the concept out. In this case, I have a tableview controller within a tableview controller.
#interface SimpleTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
// This is the controller within the controller
#property IBOutlet SecondTableViewController *secondTableController;
#property IBOutlet UITableView *secondTable;
My SecondTableViewController has this fun bit.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
UIViewController *detailViewController = [[UIViewController alloc] initWithNibName:#"SimpleNonTableViewController" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[manualViewControllerParent.navigationController pushViewController:detailViewController animated:YES];
}
The view that the user interacts with is hooked up to SimpleTableViewController. In this way, SecondTableViewController is "within" SimpleTableViewController. Feel free to comment if you'd like more details!
I've put my test/concept project on github. https://github.com/hyliandanny/TableViewCeption
You need to use a custom container controller to do what you want. It would be easiest if you used a storyboard, but you can do it in code with xibs as well. The outer controller should be a UIViewController, not a table view controller. You can do something like this (in the outer controller):
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIViewController *detailViewController = [[UIViewController alloc] initWithNibName:#"SimpleNonTableViewController" bundle:nil];
[self addChildViewController:detailViewController];
detailViewController.view.frame = set the frame to what you want;
[self.view addSubview:detailViewController.view];
[detailViewController didMoveToParentViewController:self];
}
You should read up on Apple's documentation for custom container controllers.
What you need to make sure:
Your UITableView delegate is hooked up to your controller. Otherwise it wouldn't call didSelectRow. You can do this in xib or in viewDidLoad method.
Your self.navigationController is not nil
Your detailViewController is not nil
I also think that what you mean is you have UITableView inside your UIViewController. UITableView is only the view, whereas UITableViewController is a controller. You can't have a controller inside another controller.

Resources