There is a current view as UIViewController which call "LoginView" but I'm not in, I'm in a NSObject class and I want to call, display an other UIViewController which is call "MapView". How can I do this?
The problem is like above screenshot.
At your IBAction or specific method write this:
UIWindow *window=[UIApplication sharedApplication].keyWindow;
UIViewController *root = [window rootViewController];
UIStoryboard *storyboard = root.storyboard;
CustomViewController *vcc =(CustomViewController *) [storyboard instantiateViewControllerWithIdentifier:#"storyBoardID"];
[root presentModalViewController:vcc animated:YES];
I am assuming you're trying to access your UIViewController member from a UIViewController class from a NSObject class. Easy just pass UIViewController member to the NSObject class. In this case a self. What that lets you do is you can change, edit, remove, whatever you want to do in your UIView from another class. The following is an example of that.
Calling the NSObject Class from your UIViewController class
#implementation myViewControllerClass
- (void) viewDidLoad {
//Pass in the UIViewController object, in this case itself.
[[myNSOBjectClass alloc] startViewController:self];
....
}
Then from your NSObject
#interface myNSOBjectClass{
//Global access to the view controller.
UIViewController *viewController;
}
...
#implementation myNSOBjectClass
...
//function that the caller calls to pass their UIViewController object
- (void)startViewController:(UIViewController *)callerViewController{
viewController = [[UIViewController alloc]init];
//puts the caller's view controller to the global member.
viewController = callerViewController;
...
}
Now you have the view controller at your fingertips!
Cheers :)!
I used like this in my NSObject class:
[[[UIApplication sharedApplication] delegate].window.rootViewController presentViewController:yourMapViewContorller animated:YES completion:nil];
I hope it's useful.
You shouldn't be instantiating and displaying view controllers from within a model. Views should be driven by models.
In this case you mentioned LoginView as your starting point. When some condition is satisfied (successful login perhaps?) you should update the underlying model accordingly, and then display the MapView.
From within LoginView:
MapView *mapView = [[MapView alloc] init];
If your app uses a navigation controller:
[self.navigationController pushViewController:mapView animated:YES];
Otherwise:
[self presentViewController:mapView animated:YES completion:<nil or block>];
Try this Code. It'll help to you......
In your button click action You have to send your UINavigationController & current ViewController. Because NSObject class not found that controller.
In your Button Action put this Code:
[demo login_method_called:self.navigationController withCurrentViewController:self];
In your NSObject .h class put this code:
#import <Foundation/Foundation.h>
#import "Home_ViewController.h"
#interface Method_Action_class : NSObject
- (void)login_method_called:(UINavigationController*)navigation withCurrentViewController:(UIViewController*) controller;
#end
In your NSObject .m class put this code:
#import "Method_Action_class.h"
#implementation Method_Action_class
-(void)login_method_called:(UINavigationController*)navigation withCurrentViewController:(UIViewController*) controller
{
Home_ViewController *home = [[Home_ViewController alloc] initWithNibName:#"Home_ViewController" bundle:nil];
[navigation pushViewController:home animated:YES];
}
#end
And Build your code.
I have created an obersver in view controller class and declare a method of push view controller and post notification using NSNotification centre from NSObject subclass and it is working well.
in view controller:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dismissPickerView) name:kNotificationDismissPicker object:nil];
in subclass of NSOject:
[[NSNotificationCenter defaultCenter] postNotificationName:kMoveToAchievementView object:nil];
Related
I have a Controller A and there is a UIButton, which on click I am presenting a new Controller B. But the problem is that the controller B is first embedded with a NAV. So ultimately I am presenting the UINavigationController.
Now there is a UIButton in Controller B on which the controller will dismiss and a delegate should be passed on controller A with some message
Controller A UIButtonCode
- (IBAction)summaryButtonClick:(id)sender {
UIStoryboard* storyBoard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController* summaryVC=[storyBoard instantiateViewControllerWithIdentifier:#"SummaryNavVC"];
[self presentViewController:summaryVC animated:YES completion:nil];
summaryVC=nil;
}
Now Controller B
.h file
#import <UIKit/UIKit.h>
#protocol SummaryViewWhatsNewDelegate <NSObject>
#required
- (void) SummaryViewWhatsNew:(NSString*)title;
#end
#interface SummaryViewController :
UIViewController<UITableViewDataSource,UITableViewDelegate>
{
id <SummaryViewWhatsNewDelegate> _delegate;
}
#property (nonatomic,strong) id delegate;
#property (weak, nonatomic) IBOutlet UITableView *summaryTableView;
- (IBAction)closeSummaryView:(id)sender;
#end
.m
//Button Click
[self dismissViewControllerAnimated:YES completion:^{
[_delegate SummaryViewWhatsNew:#"Sales Triggers Filter"];
}];
I have already made the implementation of delegate in my Controller A
.h
#interface ControllerA : UIViewController<SummaryViewWhatsNewDelegate>
.m of Controller A
#pragma mark -ControllerB Delegate
-(void)SummaryViewWhatsNew:(NSString *)title{
NSLog(#"Delegate Called");
}
In this case I know I haven't provided the delegate.self part as I am presenting the NAV controller and not the Controller B
So I made a Object in viewDidLoad and Controller *B and set the delegate to self. But it doesn't work and delegate is never called
On the other hand if I only present the Cntroller B without Navigation and just before presenting I keep the b.delegate=self, it works.
Another alternate can be firing Notifications. But I want to work with delegates.
So is there any way to call the delegate of the presented view controller which is embedded by Nav. Any help will be highly appreciated.
Well I got the answer
We have to fetch the Controller object from NAV
Where I a presenting I just need to add these lines and it worked
UIStoryboard* storyBoard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController* summaryVC=[storyBoard instantiateViewControllerWithIdentifier:#"SummaryNavVC"];
//Add These lines in order to get the object of Controller B.
// SummaryViewController is my Controller B
SummaryViewController* summary=[[summaryVC viewControllers] objectAtIndex:0];
summary.delegate=self;
[self presentViewController:summaryVC animated:YES completion:nil];
And it worked.
What I did:
I am using scrollview to view some UIView(s), with paging enabled.
In last page in subview of scrollView I added a button.
I also wrote a function which is in subclass of UIView ,which is invoked when we press that button.
I want to view storyboard when I press that button.
You need to implement protocol method for custom UIView class.
For example;
#import <UIKit/UIKit.h>
#protocol YourCustomViewDelegate <NSObject>
- (void)buttonTapped;
#end
#interface YourCustomView : UIView
#property (nonatomic, strong) id< YourCustomViewDelegate > delegate;
#end
And the .m file you can call buttonTapped delegate method.
- (void)myCustomClassButtonTapped:(id)sender
{
[self.delegate buttonTapped];
}
For proper work;
set your custom view delegate to self in your custom view controller.
add buttonTapped method to that view controller
And do what you want in that method. Present/Push view controllers like the other answers explained.
Edit
I will try to illustrate very simple usage of protocols, hope it will help you.
#import "MyViewController.h"
#import "YourCustomView.h"
#interface MyViewController ()<YourCustomViewDelegate> // this part is important
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
YourCustomView *customView = // initialize your custom view, I suppose that you already did it
customView.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)buttonTapped
{
YOUR_VIEW_CONTROLLER_CLASS *viewCon =[storyboard instantiateViewControllerWithIdentifier:#"mainVC"]; //mainVC is just a example and u will have to replace it with your viewController storyboard id
//Pushing VC
[self.navigationController pushViewController:viewCon animated:YES];
}
Take a look at this
YourViewController *obj=[[YourViewController alloc]init];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:obj];
[[[UIApplication sharedApplication]keyWindow].rootViewController presentViewController:nav animated:YES completion:NULL];
try like this
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController* initialView = [storyboard instantiateInitialViewController];
Firstly you need to set a storyboard Id to your ViewController, namely "mainVC". Then you could pus/present it using below code :-
YOUR_VIEW_CONTROLLER_CLASS *viewCon =[storyboard instantiateViewControllerWithIdentifier:#"mainVC"]; //mainVC is just a example and u will have to replace it with your viewController storyboard id
//Pushing VC
[self.navigationController pushViewController:viewCon animated:YES];
//OR presenting VC
[self presentViewController:viewCon animated:YES completion:nil];
Also in case if you want your another storyboard to be initiated then below,
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil]; //Change MainStoryboard with your storyboard id
hope this will help
the way i perceive your question is
->Rightnow your inside you are in UIView class and inside it there is a button by clicking it you want to push or present a ViewController and offcourse from inside your UIView class you cant push or present your view Controller. So
you can do one simple thing first inside action method make a ref(forward declaration) or you can make a whole new object of your ViewController class in which your UIView is present right now , then call a function(which exist in your ViewController) like
//function inside your uiview calss
- (void)btnaction
{
[_objCSInformationViewController pushViewController];
}
// function inside your view controller
-(void)pushViewController
{
yourViewController *objViewController = [[yourViewController alloc]initWithNibName:#"yourViewController" bundle:nil];
[strong.navigationController pushViewController:objViewController animated:YES];
}
I have two view controllers. We'll call them listViewController and mapViewController. The listViewController shows first, a user taps a button that shows the mapViewController. The user taps a button on a annotation which is where my problems start.
When the user taps a button on mapViewController, I would like to call a method listViewController and dismiss mapViewController. To do this I am using this code:
mapViewController.m
listViewController* lvc = [[listViewController alloc] initWithNibName:nil bundle:nil];
[lvc getInformation:StringParameter];
[self dismissViewControllerAnimated:YES completion:nil];
However, when executing getInformation it seems that the listViewController class has been dealloc'd because all of the objects that I initialized in the viewDidLoad on listViewController are now nil including self, which just breaks everything.
I assume I'm creating the listViewController object incorrectly in mapViewController. I've tried it with a nil for nibName with the same result.
Ok, Let me clear one thing. On listViewController, you presentViewController a mapViewcontroller right? And you want invoke getInformation of the instance from mapViewController. In the code you're added, you instantiate listViewController again. You have 2 different instance of listViewController.
One option is to use a delegate pattern:
In your MapViewController.h file:
#protocol MapViewControllerDelegate <NSObject>
-(void)dismissMe;
-(void)getInformation:(NSString *)stringParameter;
#end
#interface MapViewController : UIViewController
#property (weak)id <MapViewControllerDelegate> delegate;
#end
In your MapViewController.m file:
-(void)annotationButtonTap:(id)button
{
[self.delegate getInformation:stringParameter];
[self.delegate dismissMe];
}
In your ListViewController.h
#import "MapViewController.h"
#interface ListViewController : UIViewController <MapViewControllerDelegate>
-(void)dismissMe
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)getInformation:(NSString *)stringParameter
{
//do whatever you plan with stringParameter
}
And somewhere in you ListViewController.m file where you create the MapViewController instance:
mapViewController = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
mapViewController.delegate = self; //make sure you do this
I have an application with tab bar and 3 different View Controller. one of these imanage a UItableView that I designed through Interface Builder (storyboard) and I set the it's view controller class in the Inspector -> inspector identity -> and I set class field there, hence, I have no control when this view controller get instantiated, as it's done through storyboard when user click on tab bar. notice, i'm new to objective C and iOS programming.
the issue that I'm facing, i'm also using remote notification. hence, when I receive a remote notification message in "didReceiveRemoteNotification" in the AppDelgate class. I need to update UI interface (above ViewController), but the issue I don't have a reference (pointer) to this ViewController from my AppDelgate class ( or do I?). the problem this ViewController instantiated by storyboard nor programmatically, otherwise I could have kept a reference to it.
I did some reading and I understand I could do this communication via NSNotification, but I think this will be an overkill for a problem that maybe arise just because I'm new to this and I don't have full understanding of iOS development.
Thanks,
NSNotifications are easy to use and are probably the right solution.
In the app delegate that needs to send the message, just put:
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:someObjectYouWantToPassCouldBeAppDelegateOrRemoteNotificationObjectOrAnything];
In the view controller that is receiving the message, put:
-(void)viewDidLoad
{
[super viewDidLoad];
//you can add as many of these as you like to handle different notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"MyNotification" object:nil];
}
-(void)viewDidUnload
{
//make sure you remove every observer you've added here
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MyNotification" object:nil];
[super viewDidUnload];
}
-(void)dealloc
{
//clean up in case viewDidUnload wasn't called (it sometimes isn't)
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
//use a different handler method for each notification
//the method name should match the selector in your observe call in viewDidLoad
-(void)handleNotification:(NSNotification *)notification
{
WhateverClassOfObjectYouWerePassing *object = notification.object;
//now you have a reference to the object that was passed from your app delegate
}
For different methods you want to call, just and a new notification name and a new handler method.
Your app Delegate will have a window property which points to the apps window.
Window Property has a -rootViewController property/method.
For your Tab Based Application it would return you the TabViewController.
Each TabViewController have a method -(NSArray *)viewControllers which returns the ViewControllers inside the Tab. These are arranged in the order.
To Access your applications AppDelegate use [[UIApplication sharedApplication]delegate]
Once you have these viewcontrollers you would know which all viewController these are since you have added it in the XIB files. and can perform your methods
1. Communicate two ViewControllers
If you want to communicate two ViewControllers, you should use #protocol as Apple recommended:
ViewController1.h
#interface ViewController1 : UIViewController<ViewController2Delegate, ViewController2DataSource>
#end
ViewController1.m
- (IBAction)goToViewController2:(id)sender{
if(viewController2 == nil) {
ViewController2 *viewController = [[ViewController2 alloc]
initWithNibName:#"View2" bundle:[NSBundle mainBundle]];
viewController2 = viewController;
}
//...
viewController2.delegate = self;
viewController2.dataSource = self;
[self.navigationController pushViewController:viewController2 animated:YES];
}
- (NSString)viewController:(ViewController2 *)controller itemForSomethingAtIndex:(NSInteger)index{
//Send to viewController2 what it needs
return [items objectAtIndex: index];
}
- (void)viewController:(ViewController2 *)controller didFinishEnteringItem:(NSString *)item{
//Handle the result from the viewController2
NSLog(#"result: %#", item);
}
ViewController2.h
#import <UIKit/UIKit.h>
// Define your delegate methods to return items to the delegate of this viewController
#protocol ViewController2Delegate <NSObject>
- (void)viewController:(ViewController2 *)controller didFinishEnteringItem:(NSString *)item;
#end
// Define your dataSource methods to send items from the dataSource to this viewController
#protocol ViewController2DataSource <NSObject>
- (NSString)viewController:(ViewController2 *)controller itemForSomethingAtIndex:(NSInteger)index;
#end
#interface ViewController2 : UIViewController
#property (nonatomic) id <ViewController2Delegate> delegate;
#property (nonatomic) id <ViewController2DataSource> dataSource;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize //...;
- (void)someMethod {
//Get someThing from controller1
NSString *item = [dataSource viewController: self itemForSomethingAtIndex:0];
//Return someThing to controller1
[delegate viewController: self didFinishEnteringItem: item];
}
2. Communicate backgroundTask with viewController
If you want to communicate a background task or handle a push notification, use #NickLockwood's answer. But this dont gonna work if the viewController its not loaded. In this case you should handle that in the AppDelegate:
//Get the appDelegate instance
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//And call your custom method to show what it needs
[appDelegate customMethod];
Your custom method should call controllers consecutevly like:
AppDelegate > RootController > ViewController1 > ViewController2 > myMethod
//do something if viewController2 is visible to the user or push it before do something.
//if you use navigation controller, then you need to ask for the position and className
I have the following code pushing a UIViewController. This code is a target method that gets executed when a UIButton is pressed:
-(void)pushNavigationController
{
ParameterListerViewController *plvc = [[ParameterListerViewController alloc] init];
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:plvc];
self.navigationController.navigationBarHidden = YES;
plvc.numberOfParameters = [[numberOfTrialsField text] intValue];
NSLog(#"about to push the navigation controller");
[self.navigationController pushViewController:nvc animated:YES];
}
It gets until the NSLog statement, but after that, the view controller never gets pushed and the app just crashes. Here is the header file of ParameterListerViewController:
ParameterListerViewController.h
-------------------------------
#interface ParameterListerViewController : UIViewController<UITextFieldDelegate>
{
UIScrollView* scrollView;
}
#property(nonatomic) NSInteger numberOfParameters;
#end
Here's the header file which contains the UIButton and the respective target method which contains the code for pushing the navigation controller.
SettingsViewController.h
------------------------
#interface SettingsViewController : UIViewController <UITextFieldDelegate, UIPickerViewDelegate, UITableViewDelegate, UITableViewDataSource>
{
id <SettingsViewDelegate> delegate;
}
#end
And here's the header file of a class object that DOES GET PUSHED:
#interface ItemViewController : UITableViewController
{
}
#end
Any suggestions?
Your nav controller's view has to be in the view hierarchy.
Unless the nav controller is set as the rootViewController of a UIWindow, it needs to be explicitly added.
Try this:
[self.view addSubview:self.nvc.view];
If this is the case, you won't need to do the pushViewController - the plvc will already be visible.