displaying a ViewController from a non UI class - ios

I perform some data loading tasks from an Ojective§C class and once everything is loaded, I simply wants to display a Viewcontroller subclass prepared in a storyboard.
So when everything is ok, the following method is called:
- (void)loadingNextView
{
CABBndGSite *mySite = [CABBndGSite alloc];
CABBndGSelectLanguageViewController *vc = [[mySite myRootViewController].storyboard instantiateViewControllerWithIdentifier:#"SelectLanguageViewController"];
[[mySite myRootViewController] presentViewController:vc animated:YES completion:nil];
}
So I verified that myRootViewController is not nil. It's a UINavigationController class.
vc is not nil so it found my view in the storyboard.
Anyway, the presentViewcontroller message seems to doing what expected.
Certainly a stupid mistake but my poor iOS programming knowledge lets me in the fog!
I use this code from ViewController subclasses with success and as here I get a valid ViewController pointer, I don't understand why it doesn't work.
I also tried to implement the AppDelegate method explained here How to launch a ViewController from a Non ViewController class? but I get a nil navigation pointer. Maybe something not well connected in my application
May I have some explanation?
Kind regards,

UINavigationController maintains a stack of view controllers. You can access this stack through the viewControllers property. To present your view controller, you can:
(a) have the navigation controller push the new view controller on to
the stack (pushViewController:animated:);
(b) have the top view controller in the view controller stack present
the new view controller modally (presentViewController:animated:completion:), or;
(c) add the new view controller to the view controller stack array
manually by assigning a new viewControllers array to the navigation
controller's viewControllers property (setViewControllers:).

Related

how to pass a variable back to root navigation controller from the UIViewController using Protocol and Delegate in Swift

Xcode Image
As you can see in the image attached I have the root navigation controller called - Notifications and a UIViewController called NotificationsController.
So my Question is how can i pass a variable from NotificationsController back to Notifications using Protocol and Delegate, because in this case there is no segue but a default relationship between them.
Is my question correct or is there another way to do what i need.
Any help is really appreciated
To reference the navigation controller from the view controller (it is an optional so you need to handle that):
// self is a UIViewController
self.navigationController
To reference the view controller from the navigation controller:
// self is a UINavigationController
let index = // Index of the view controller. You may need to iterate over viewControllers to find this.
self.viewControllers[index]
You don't really need to set up a delegate. As keithbhunter pointed out in his answer, a view controller has a navigationController property that will point to the navigation controller that manages it.
I suggest you define a protocol for the messages you want to send to your navigation controller, and then have your custom subclass of UINavigationController conform to that protocol.
Within the view controllers that are on the navigation controller's stack you can fetch a pointer to your navigation controller and cast it to type UINavigationController<myNavControllerProtocol>.
(UINavigationController that conforms to myNavControllerProtocol. I'm working in Objective-C these days and don't remember the exact syntax for that.)

ContainerView childViewControlllers view frame taking whole screen

Please see the following attached image for more understanding.
The scenario is : I have five view controllers
Each view navigate to next viewController on push
Now the MidContainerViewController has got the Container which embeds the FirstViewController.
Bottom of MidContainerViewController is a static view which should not change while navigating further.
On navigation The FirstViewController should be of size equal to container
Also when I navigate to SecondViewController from FirstViewController, it should also be of size of Container.
Objective 1 : 'FirstViewController' and 'SecondViewController' should not take whole screen overlapping the bottomView image on MidContainerViewController.
Objective 2 : I must pop to root "View Controller" on last 'push' on SecondViewController.
Solutions :
1) Currently As I have embedding the root "View Controller" to navigationController. No problem with objective 2. It successfully navigates back to root. But can't achieve objective 1
2) If I embed the "First View Controller" too with navigationController the objective 1 is achieved but start facing problem for objective 2. It pop back till 'MidContainerViewController' only.
Any suggestion are highly appreciated.
Thanks,
Assuming your are manually handling push/pop events without using storyboard, I recommend you to not push the FirstViewController from MidContainerViewController. Add the next view controller as child view controller through following code:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[self addChildViewController:navController];
[navController.view setFrame:CGRectMake(0.0f, 0.0f, _containerView.frame.size.width, _containerView.frame.size.height)];
[_containerView addSubview:navController.view];
[navController didMoveToParentViewController:self];
From the above code you'll achieve your first objective. In the above code, the FirstViewController gets initiated on its own separate navigation controller object, so it will have different navigation stack. So if you further push and pop from FirstViewController & SecondViewController, your view will not take the whole screen. But if you call popToRootViewController from last view controller, your root view controller would be FirstViewController in that specific container view.
To achieve second objective, you'll have to create a public property to contain reference of main navigation controller object in your AppDelegate class. Create your root view controller from that navigation controller object. In your last view controller, you'll then have to get reference of that navigation controller property from your AppDelagate class and then call popToRootViewController from that object.
i think you must present your root view controller from the secondView Controller rather that embedding to root view controller.
Thank you everyone.
The problem is solved and both the objectives are achieved.
I kept only one navigation controller as root view controller.
I created one customContainerViewController.
This class has instances of all the children it is supposed to show.
This class acts as delegate for each of its childViewController. Make customContainerViewController as deleagte of each childViewController.
I updated the chilren using delegation method and using UIView transition method in UIKit.
This worked for me.

Show custom view after person is selected in peoplePickerNavigationController

I'm running into trouble with what I think is a pretty basic task. Within peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: i want to show my own view rather than the standard person view. I'm using a Storyboard, but don't think I can simply manually segue to a window here so I'm thinking I need to create a new XIB with a View Controller in it. I'm setting the Class of the View Controller to my custom View Controller in IB. Then in peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: I'm doing:
MyVC *myVC = [[MyVc alloc] initWithNibName:#"XIBFileName" bundle:nil];
[self presentModalViewController:myVC animated:YES];
In my View Controller initWithNibName gets called, but not viewDidLoad. What am I doing wrong here?
Just try [peoplePickerVC presentModalViewController:myVC] instead of presenting from self.
The issue is that the peoplepickerviewcontroller will be in the top of the navigation stack. Becuase you wud've presented the peoplepicker from self. As this is the case, you wont be able to present/push from self as its not at the top of the navigation stack.
Otherwise once the peoplepicker has been poped, then you can further present from self.

Navigate to Root ViewController From Modal

I have a root view controller (RVC) that opens up a Modal ViewController (MVC). I then navigate within the MVC to few more VC's via a push. What is the best practice to get from one of those VC's back to the RVC?
Normally I have a delegate from the Modal VC that calls up to the RVC which then dismisses the modal, but if you navigate away from it, but I'm not sure how I would do that if you navigate away from it.
Without seeing any code it is a bit hard to help but let me shoot in the dark here.
I will assume that the first controller presented inside the modal view provides the protocol/delegate to call the dismiss action.
If you use UINavigationController inside your modal view to push other view controllers on the stack you can always obtain the first controller like this
UIViewController * yourFirstController = [[[self navigationController] viewControllers] objectAtIndex:0];
// and then use your delegate to call your dismiss method
// you will need to typecast your controller based on your subclass otherwise will get warning here
if ([[yourFirstController delegate] respondsToSelector:#selector(yourCloseProtocolMethod)]) {
[[yourFirstController delegate] yourCloseProtocolMethod];
}
Don't forget that a delegate doesn't have to be a property of a UIViewController inside your model navigation stack. Consider creating a singleton class that holds a reference to the rootviewcontroller as a delegate. That way any class in your application has access to it and you aren't forced to continually pass it through to every UIViewController that requires it.

How to send message to a parentViewController that is a subclass of UIViewController?

I have a UIViewController (MyViewController) and another view controller i'm presenting modally though MyViewController (call it SecondViewController). I want to be able to send a message to MyViewController from SecondViewController by using
[self.parentViewController hideSecondViewController];
But since parentViewController is defined as a UIViewController, and hideSecondViewController isn't a method of UIViewController, I get a warning saying "UIViewController may not respond to 'hideSecondViewController'". It works fine, because it CAN send the message successfully during the program, but since I #import SecondViewController in MyViewController, I can't #import MyViewController in SecondViewController. Any way around this?
When it comes time to dismiss a modal
view controller, the preferred
approach is to let the parent view
controller do the dismissing. In other
words, the same view controller that
presented the modal view controller
should also take responsibility for
dismissing it whenever possible.
Although there are several techniques
for notifying a parent view controller
that it should dismiss its modally
presented child, the preferred
technique is delegation.
In a delegate-based model, the view
controller being presented modally
must define a protocol for its
delegate to implement. The protocol
defines methods that are called by the
modal view controller in response to
specific actions, such as taps in a
Done button. The delegate is then
responsible for implementing these
methods and providing an appropriate
response. In the case of a parent view
controller acting as a delegate for
its modal child, the response would
include dismissing the child view
controller when appropriate.
Read more at the View Controller Programming Guide for iOS.
P.S:
since I #import SecondViewController
in MyViewController, I can't #import
MyViewController in
SecondViewController.
To solve a circular dependency problem you can use a forward declaration.
It would be better to redesign your architecture as albertamg proposed but this should work:
[self
dismissModalViewControllerAnimated:YES];
you can call dismiss on both the presenting and presented view controller and it will do the same thing.

Resources