Maximus S
Maximus S

Reputation: 11095

How to show a view programmatically

enter image description here

Above is my storyboard. The first view is hooked up to ViewController, and the second isn't connected to anything. I know how to show the second view controller if I had a button on the first. I can click and drag from the button to the second view, creating a segue. However, this time, I have to show the second view controller programmatically inside ViewController.m. For example, in when some function myFunc is called, I want to show the second view controller. Could someone explain how I can do this?

I think I need to know the followings:

  1. How to reference the second view controller in ViewController.m
  2. How to open the second view controller

Thank you!

UPDATE:

//setSelectedDate is myFunc. It lives inside myView.m, which is a subview of UIView

- (void)setSelectedDate:(NSDate *)newSelectedDate; {
    NSLog(@"override worked");
    [super setSelectedDate:newSelectedDate];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    UIViewController *firstController = [storyboard instantiateViewControllerWithIdentifier:@"InitialViewController"];
    UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:@"MySecondViewController"];
    [firstController presentViewController:myController animated:YES completion:nil];
}

I get the following warning if I do above:

Warning: Attempt to present on whose view is not in the window hierarchy!

and from this post I believe it's because I am doing it in the wrong place. How can I resolve this issue?

**Update 2: I did the following: **

- (void)setSelectedDate:(NSDate *)newSelectedDate; {
    [super setSelectedDate:newSelectedDate];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];

    UIViewController *firstController = [storyboard instantiateViewControllerWithIdentifier:@"InitialViewController"];

    [firstController performSegueWithIdentifier:@"GoToSecondViewController" sender:firstController];

The warning is gone, but the view controller is still not showing. Is it because I am calling this inside a View instead of a ViewController?

Upvotes: 1

Views: 143

Answers (2)

ahruss
ahruss

Reputation: 2130

To avoid tightly coupling these components, here's how I'd do it.

In myView.h, add a delegate protocol to which your InitialViewController will conform, and a property of that type to the myView class:

@class myView;

@protocol myViewDelegate 
-(void)datePickerDidChangeValue:(myView*)view;
@end

@interface myView : UIView 
@property IBOutlet id<myViewDelegate> delegate;
// ... other members ...
@end

And in its implementation call that delegate method in the setSelectedDate: method:

-(void)setSelectedDate:(NSDate*)selectedDate
{ 
    _selectedDate = selectedDate;
    [self.delegate datePickerDidChangeValue:self];
}

Then, set the delegate property in InterfaceBuilder to be your InitialViewController. Right click on your custom view and then drag from the delegate outlet to your ViewController:

Screenshot of Interface Builder

Then, in InitialViewController.h, set it to conform to the myViewDelegate protocol:

#import "myView.h"

@interface InitialViewController : UIViewController<myViewDelegate>
// ... members ... 
@end

and implement that delegate method, something like this, assuming you've set up the identifiers as described in this answer:

-(void)datePickerDidChangeValue:(myView*)view 
{
    NSDate* theDate = view.selectedDate; // do whatever you want with this value

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:[NSBundle mainBundle]]; 
    UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:@"MySecondViewController"];
    [self presentViewController:myController animated:YES completion:nil];
}

Upvotes: 1

Ilea Cristian
Ilea Cristian

Reputation: 5831

You could do one of the following:

Create a segue in your storyboard by dragging from the firstViewController to the second one. Then give that segue a name (fill the Identifier field, under Attributes inspector on the right pane in Interface Builder). Let's say "GoToSecondViewController".

In your myFunc method (or function), call

[self performSegueWithIdentifier:@"GoToSecondViewController" sender:nil];

OR

Give your second viewcontroller a storyboard ID. From the interface builder, click on your second viewcontroller. On the right pane under "Identity inspector" fill in the Storyboard ID field. Let's say "MySecondViewController".

In your myFunc method (or function) do the following:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:[NSBundle mainBundle]]; // or whatever your storyboard is called
UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:@"MySecondViewController"];
[self presentViewController:myController animated:YES completion:nil]; // present it or push it if you have a navigation controller

Upvotes: 2

Related Questions