I have a UIViewController with a container view which holds a UITableView.
Within the UITableView I have a NSFetchController with NSPredicate that uses variables from the intial UIViewcontroller (I hope your still with me). For one instance that the user changes the container view does not update.
How can I force a reload/update on the container view when this occurs? I looked around but did not see much on this topic.
To be specific I have a UIDatePicker that changes the date on a button. It is this that needs to be updated.
From the initial UIView controller, you can get a reference to the table view controller with self.childViewControllers[0]. So, you need to do it like this:
UITableViewController *tbc = (UITableViewController *)self.childViewControllers[0];
[tbc.tableView reloadData];
You wrote that you have UIViewController there and not UITableViewController - if you have UIViewController you have to have a property there. I assume that here everything is ok.. But check.
What I am doing while working with containers views is adding element by:
_someVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SomeVC"];
[self addChildViewController:_someVC];
_someVC.view.frame = _containerView.bounds;
[_containerView addSubview:_someVC.view];
[_someVC didMoveToParentViewController:self];
And not with IB. Hope that helps.
Related
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];
Here is the problem I am having. I am unable to set the UINavigationBar title for the views I have contained within a UIPageViewController.
The basic architecture of the app is as follows.
The root view controller for the app is a UITabBarController, with 5 navigation controllers contained in it.
The first Navigation controller, which is the one I am having issues with, contains a page view controller and this page view controller contains a number of UIViewControllers.
I want that, when I swipe through each of these view controllers, I can set the title in the UINavigationBar.
I have tried the following:
In the UIViewController contained within the page view controller, I have tried [self setTitle:#"Title I want"] - it didn't work.
Within the same UIViewController I have also tried [self.navigationBar.navigationItem setTitle:#"Title I want"] - this also didn't work.
I also tried setting the title for the View controller and attempted to extract that inside the PageViewControllers delegate method transitionCompleted, but this didn't work either.
I am wondering should I go back to the drawing board, and whether I am going down a rabbit hole with this view layout architecture. Has anyone else encountered this issue and if so, how did you solve it?
Edit: I must also add that I am doing this programatically.
Thanks for the help.
So, in the end I came up with a way to get this working, albeit not the cleanest solution that I wanted, but suitable for the purpose nonetheless.
I created a new class called PageLeafViewController and set up its init method as below. Child view controllers of a page view controller inherit from this. Here is the code.
Code sample
- (id)initWithIndex:(NSUInteger)index andTitle:(NSString *)navBarTitle; {
if(self = [super init]) {
self.index = index;
self.navBarTitle = navBarTitle;
}
return self;
}
These can be initialised like so before being added to the UIPageViewController.
Code sample
ChildViewController *aChildViewController = [[ChildViewController alloc] initWithIndex:1 andTitle:#"A Title"];
You will need to add a UIPageViewControllerDelegate to your interface for your page view controller. This is so you can implement the code for the delegate methods for when your view transition has been completed, and you need to set the title.
When the UIPageViewController loads, I grab the first view controller and get its title, setting it to the UINavigationController navigation bar
Code sample
PageLeafViewController *initialViewController = (PageLeafViewController *)[self viewControllerAtIndex:0];
[self.navigationItem setTitle:initialViewController.navBarTitle];
When a transition occurs, we set the title again to that of the new child view controller, when the transitioning into view has completed.
Code sample
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
PageLeafViewController *currentLeaf = (PageLeafViewController *)[self.pageViewController.viewControllers lastObject];
[self.navigationItem setTitle:currentLeaf.navBarTitle];
}
Note: The above gets called automatically when a new child view controller has been displayed.
While this is not the most elegant solution it works for now, and I don't think its possible to call a function from within a child view to update the NavigationBar title, unless someone wants to correct me?
Hope this helps.
I don't think you're supposed to set the title on the navigationBar, have you tried self.navigationController.title = #"Title"; ?
This is puzzling me.
The context
The original tutorial I'm following.
Where the segue is added to the Main View via a custom segue:
- (void) perform {
MainViewController *source = (MainViewController *)self.sourceViewController;
UIViewController *destination = (UIViewController *) self.destinationViewController;
for(UIView *view in source.main.subviews){
[view removeFromSuperview];
}
source.currentViewController = destination;
destination.view.frame = CGRectMake(0, 0, source.main.frame.size.width, source.main.frame.size.height);
[source.main addSubview:destination.view];
}
The TextField is connected as delegate in the child View Controller. All things being equal I get the app crashed without any message.
The workaround
In the Main View Controller, in -(void)prepareForSegue: I've added [segue.destinationViewController setDelegate:self]; in the meantime I've added a property in the child View Controller id<UITextFieldDelegate> delegate and modified the textfield delegate as self.delegate.
This works, but the trouble is that I've to set the delegated methods in Main View Controller which is not quite efficient as I have more View Controllers to add.
The Objective
How do I set each View Controller to be the delegate for itself without crashing?
The immediate cause of your error is that the view controller that your views belong to is being deallocated. The fact that your views are on screen while their view controller is deallocated highlights a fundamental flaw in the approach of taking views off one view controller and adding them to another. View controller containment is the correct way to solve an issue like this.
Changing the currentViewController property to strong will fix the memory management issue you're seeing, but it's just a bandaid. Your currentViewController will still be missing rotation methods, appearance and disappearance methods, layout methods, and so forth. View controller containment ensures these methods get called for the view controller whose views are on screen.
Here is an altered version of your project that illustrates how to use view controller containment. I think that will be a better solution than manually removing and adding subviews of the view controllers themselves. See the Apple docs for more info on custom view controller containers.
At first, let's see crash report. Please, do the following:
1. Add Exception Breakpoint
2. Edit it as in the picture
You should create a custom class for the destinationViewController wich will implement UITextFieldDelegate
#interface DestinationViewController <UITextFieldDelegate>
#end
And from storyboard add the class to UIViewController that has TextField
And make the connections for elements and TextField delegate.
Implement delegate methods.
You will not need the implementation of prepareForSegue: anymore. You will have two different classes with different elements. Only if you need to pass something from source to destination then you use prepareForSegue:
Hope you'll understand
Hy
i have two classes uiviewcontroller and uiview. I have one view controller. Inside i have uiview. Inside uiview i have textfield and when i write a text and click done i need to refresh uiviewcontroller.
I tried with this in uiview class:
-(IBAction)textFieldReturn:(id)sender
{
ViewController *vc = [[ViewController alloc] init];
[vc viewDidLoad];
}
i need refresh the same as you click the button and open viewcontroller.
I am guessing you mean that you want to "refresh" the view, not the view controller. To do that simply call [self setNeedsDisplay] from the view, or [self.view setNeedsDisplay] from the view controller. Also make sure that the textfield is a subview of the uiview. Either do that in the nib file or in code by calling [self addSubview: (textfield here)].
Also, if you want to access the view controller from the view you will need to create an IBOutlet, simply allocating a new ViewController object within the view does not mean that the created view controller controls the view. Hopefully that makes sense. I'd recommend going through some ios starter tutorials as well. Just google that there are a lot.
I have a view controller embeded in another view using 'addSubView' that is not catching events, how can I make sure it does?
background:
I'm attempting to nest views in order to break up a storyboard that is to be shared by multiple devs. To accomplish this with minimal duplication of functionality I/we have created a mainStoryboard which contains a tab controller and 4 tabs, each tab contains a subview that loads a UIView (contained in another storyboard) into itself. These views are added like so:
//Add sub view
UIStoryboard *board = [UIStoryboard storyboardWithName:#"MessagesStory" bundle:nil];
UIViewController *boardController = [board instantiateInitialViewController];
[self.view addSubview:boardController.view];
boardController.view.frame = CGRectMake(0, 0, 320, 480);
The initial view controller that is loaded is a UITableView subclass, the whole thing works great for rendering the table and it's contents to the screen and I can interact with the table and select rows, however the event listener on the the views controller 'didSelectRowAtIndexPath' fails to fire.
I know it's not firing thanks to good ol' NSLog():
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Please kind sirs help a poor string appear in the console.");
}
I know it is related to the subview because if I load the subview on it's own as the main view the event listener functions properly.
Any help is appreciated as this is taking longer than expected and I may be pulled to another project before I can finish implementing this.
I figured it out.
It was stunningly simple but I had to do quite a bit of reading to find the answer. All my searches where for 'addSubView' tutorials and examples I didn't even know 'addChildViewController' existed.
Anyway I believe it's this simple:
-(void)viewDidAppear:(BOOL)animated
{
if (firstLaunch) {
firstLaunch = NO;
//Find the view controller in the other storyboard
UIStoryboard *board = [UIStoryboard storyboardWithName:#"MessagesStory" bundle:nil];
UIViewController *boardController = [board instantiateInitialViewController];
//add it as a child view controller (THIS IS WHAT I WAS MISSING)
[self addChildViewController:boardController];
//now it is okay to add the subview
[self.view addSubview:boardController.view];
//trigger this method (also missing this but it will run without it, I assume is good practice)
[boardController didMoveToParentViewController:self];
}
[super viewDidAppear:animated];
}
Once I knew I wanted to 'addChildViewController' it was easy to find information:
How does View Controller Containment work in iOS 5?
Is it wise to "nest" UIViewControllers inside other UIViewControllers like you would UIViews?