Pushing a new UIViewController from a separate class - ios

I currently have written a slider (similar to the Facebook app) for my app. At the top of the slider is a Search Box, and the methods controlling the search functionality are also within the app delegate.
Similarly, I have the methods that control the slider's table view in a separate class (SliderMenuViewController).
I am looking for a way for the slider (either the search box or the tableview cells) to be able to tell the RootViewController (or whichever viewController is currently visible) to push a new ViewController (inside a UINavigationController).
This is what I tried to do (this code is in the AppDelegate):
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
NSLog(#"Searching for: \"%#\"",searchBar.text);
[searchBar resignFirstResponder];
IndexAndSearch *vc = [[IndexAndSearch alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
}
But it doesn't work (it writes to the log, but doesn't push the new ViewController). I also tried sending a message to the RootViewController like this:
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
NSLog(#"Searching for: \"%#\"",searchBar.text);
[searchBar resignFirstResponder];
RootViewController *vc = [[RootViewController alloc]initWithNibName:nil bundle:nil];
[vc performSearchFromDelegateSlider];
}
With the following code in the RootViewController's implementation file:
-(void)performSearchFromDelegateSlider{
NSLog(#"Searching");
IndexAndSearch *vc = [[IndexAndSearch alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
}
But once again it only wrote to the log, not pushing a viewController.
I've looked far and wide on Google and SO, but haven't been able to find anything useful. This question is similar to mine, but there haven't been any suitable answers. I know the answer probably involves delegation, but I can't wrap my head around a solution for this.
Important note: This slider is available from nearly every ViewController in the app, meaning that whatever solution I implement has to be able to push a new ViewController for every class. That is why I can't use a solution like this one (I would have to enter the NavigationDelegate code into each ViewController, which won't work in an app as large as mine).
Thanks in advance for your help guys.

I'm not convinced it is the best solution, but I was able to get this working using notifications. For anyone that is interested, here is what I did:
Step 1
The first step is to register for the notification in the RootViewController's viewDidLoad method:
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveNavSliderSearchNotification:) name:#"navSliderSearchNotification" object:nil];
}
Step 2
I then need to fire the notification when the search is performed from the slider. The searchBar code is located in my AppDelegate and looks like so:
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
//Write to the log
NSLog(#"Searching for: \"%#\"",searchBar.text);
//Dismiss the keyboard
[searchBar resignFirstResponder];
//Post the notification (to be used by the RootViewController
[[NSNotificationCenter defaultCenter] postNotificationName:#"navSliderSearchNotification" object:self];
}
Step 3
I then need to write the didReceiveNavSliderSearchNotification class (which will be called in the RootViewController when the navSliderSearchNotification notification is posted and received):
-(void)didReceiveNavSliderSearchNotification:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"navSliderSearchNotification"])
NSLog (#"Successfully received the search notification!");
//Push the next ViewController when the *navSliderSearchNotification* is received
IndexAndSearch *vc = [[IndexAndSearch alloc]initWithNibName:#"IndexAndSearch" bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
}
And that is how I managed to push new viewControllers from a separate class (in this case the App Delegate, but I also have it working from other classes as well).
Final step (optional)
My slider is accessible from everywhere in the app, so I did not unregister from my notifications in the RootViewController (meaning these methods will continue to fire even if the user has been pushed to another viewController). If you do not want this functionality, make sure to unregister from these notifications using the following code (it would go in the RootViewController):
-(void)viewWillDisappear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"navSliderSearchNotification" object:nil];
}
Like I said, I am not entirely convinced this is the best method. If you have another solution that you prefer, please feel free to post it.

Have you tried doing this:
Create a UIViewController variable in your AppDelegate that always references the current UIViewController on the screen (You might need to set the current controller every time you create a view controller)
Once that's all done.
In your AppDelegate use
[self.currentViewController.navigationController pushViewController:anotherNewViewController animated:YES];

Related

How to dismiss multiple view controllers which have been presented not pushed?

Scenario:
I need to show 3 or more popups one after the other on button click in each popup. I have created a different viewcontroller and xib files for each popup. So for displaying each popup I have used presentViewController instead of pushViewController.
That is, I have used this:
[self presentPopupViewController:searchPopUpView animationType:0];
instead of
[self.navigationController pushViewController:searchPopUpView animated:YES];
For dismissing a popup, the following code has been written:
[self dismissPopupViewControllerWithanimationType:0];
Issue:
The popups are displaying perfectly, but the background gets darker and darker whenever a popup shows up. After all popups have been dismissed I have to finally click on the blank screen to remove those darker parts. How to overcome this issue?
I think you are using MJPopupViewController to show pop-up.
If it is so, Then try this.
Suppose there is a controllerA from which you want to show a pop-up controller popupControllerB.
Then in your controllerA add Notifications Observer
Code to write in controllerA :
// Add Notification Observer when your view initialise.
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(dismissPopup) name:#"DISMISS_POPUP" object:nil];
In viewWillDisappear remove the notifications observer
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This method will be called when you Post-notification from your popupControllerB
-(void)dismissPopup {
[self dismissPopupViewControllerWithanimationType:MJPopupViewAnimationFade];
}
And In popupControllerB, Where you want to dismiss the Pop-up, write this code.
[[NSNotificationCenter defaultCenter] postNotificationName:#"DISMISS_POPUP" object:nil];
Above line of code will call a method written in your controllerA and dismiss the pop-up properly.
If you want to dismiss presented UIViewControllers you can use this code. I have used this approach to dismiss presentedViewControllers. It will dismiss all your presentedViewControllers on your rootViewController.
UIViewController* presVC = self.window.rootViewController;
while (presVC) {
UIViewController* temp = vc.presentingViewController;
if (!temp.presentedViewController) {
[vc dismissViewControllerAnimated:NO completion:^{}];
break;
}
vc = temp;
}

When user tap push notification, what is the best way to close current viewcontroller and open new viewcontroller

When user tap push notification, what is the best way to close current UIViewController and open new UIViewController?
for example,
A(Base UIViewController) open B(UIViewController) and open C(UIViewController)
and use tap home button, so app will enter background,
after then when a user receive a push notification, and tap it,
app will enter foreground.
I want to close B, C UIViewController(C controller may be opened or not), and open D(UIViewController)
like this A->D
Would you give me some tips?
Well, when you will come from push, that means you will be coming from didReceiveRemoteNotification.
Write below line of code in didReceiveRemoteNotification
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
[navigationArray removeAllObjects]; // This is just for remove all view controller from navigation stack.
// [navigationArray removeObjectAtIndex: 2]; // You can pass your index here
self.navigationController.viewControllers = navigationArray;
[navigationArray release];
I hope this is clear.
Note: As you are accessing navigation controller in app delegate, use below to access navigation controller.
(UINavigationController *)self.window.rootViewController
The method I've followed was, in AppDelegate.m file you can implement the
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
Inside that you can have mechanism to identify the type of notification and according to that you can post your own notification using NSNotificationCenter
[[NSNotificationCenter defaultCenter] postNotificationName:#"openMyView" object:nil userInfo:myInfoDic];
Then inside notification observer method, you can perform a segue to your UIViewController that needs to display
[self performSegueWithIdentifier:#"toMySegue" sender:myDataDic];
You have to create the segue with the mentioned name in storyboard too. Hope you are familiar that process already.

Updating uilabel in view controller underneath another

I have two view controllers, FirstViewController and FourthViewController. FirstViewController is my initial view controller. I present FourthViewController with
UIViewController *fourthController = [self.storyboard instantiateViewControllerWithID:#"Fourth"];
[self presentViewController:fourthController animated:YES completion:nil];
Then, in FourthViewController's .m I'd like to change the text of a UILabel in FirstViewController. So I use
UIViewController *firstController = [self.storyboard instantiateViewControllerWithID:#"First"];
firstController.mainLab.text = [NSMutableString stringWithFormat:#"New Text"];
However, after I use
[self dismissViewControllerAnimated:YES completion:nil];
I find that my mainLab's text has not updated. Does anyone know why?
When you are calling this line from FourthViewController.m you are actually creating a new instance of FirstViewController, rather than using the already created one.
UIViewController *firstController = [self.storyboard
instantiateViewControllerWithID:#"First"];
You can tackle this in two ways.
1) Using notification
post a notification from FourthViewController when label text need to be changed.
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateLabel"
object:self];
In your FirstViewController viewDidLoad methodcreate an observer that waits for this notification to get fired.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateLabelCalled:)
name:#"updateLabel"
object:nil];
Implement updateLabelCalled: and update label.
- (void) updateLabelCalled:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"updateLabel"]){
//write code to update label
}
}
2) Implementing delegate
It is already explained here in stackoverflow. The basic idea is you create a FourthViewController delegate, and create a delegate method to updateLabel. FirstViewController should implement this method.
If you want to update the label on first screen and nothing else then go for notifications. It's better rather you write the delegate. Because you want to update only label text thats it.

Go back to initial view controller from a class

I'm building an app use bluetooth for communication, and I have a class called EAController(NSObject) to handle the accessory delegate.
So if the phone lost bluetooth communication, an accessory delegate method is called in EAController where I can show an alert. What I want to do is to when lost communication, show an alert and go back to the initial view controller.
I know I can add a notification, and have all the view controllers listen to that, and the current view controller can take care of the "Go Back to First View Controller" action.
But my app has so many view controllers, so is there any way I can go back to the initial view controller through the EAController class?
Thanks.
Handle the notification in your app delegate.
Your explanation was a little vague, some code might help me understand the problem better but it sounds like UINavigationController popToRootViewControllerAnimated: might be what you are looking for.
If EAController is a UIViewController, and has been added a navigation controller, it should have a reference to the nav controller to call the method.
If you're using a UINavigationController you could us the
-popToRootViewControllerAnimated: method
If you are working with storyboards and segues you should look into unwind segues. There are several good tutorials on the net., eg.
http://cocoatouch.blogspot.nl/2013/02/unwinding-segues-in-storyboard.html
if you are using UInavigationController:
for(UIViewController* vc in self.navigationController.viewControllers) if([vc isKindOfClass:FirstViewController]
{
[self.navigationController popToViewController:vc anmated:YES];
break;
}
popToRootViewControllerAnimated: will do what you want. If you are in a part of the code where you do not have direct access to the UINavigationController you can push an event and configure your navigation controller to receive it. Like so:
Where you have your navigation controller:
UINavigationController *navController = [[UINavigationController alloc] init];
// subscribe to the notification
[[NSNotificationCenter defaultCenter] addObserverForName:#"goBack!"
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
// pop!
[navController popToRootViewControllerAnimated:YES];
}];
Now, somewhere else in the code... do this when you want to go back:
// post the notification
[[NSNotificationCenter defaultCenter] postNotification:
[[NSNotification alloc] initWithName:#"goBack!"
object:nil
userInfo:nil]];

Send data to another view using Prebuilt UITabBarController?

I have created a Tab Bar Application using Xcode that as two views.
The secound view is a UITableViewController.
What I am struggling to do is send data to this view, when the second tab is pressed. I have delegated the Tab Bar to my AppDelegate class and implemented this function:
-(void)tabBarController:(UITabBarController*)tabBarController didSelectViewController:(UIViewController*)viewController
{
// Override point for customization after application launch.
statisticsViewController* assignmentListcont = [statisticsViewController alloc];
NSManagedObjectContext* context = [self managedObjectContext];
assignmentListcont.managedObjectContext = context;
[assignmentListcont release];
}
The second view is displaying fine but the data hasn't been passed. I imagine its because I haven't programmed the second views transition but I'm unsure of how to do this if I already have a .xib file doing it for me? Is there some way to just pass the data without problems or even retrieve the data once inside the view?
You could use notifications.
In the view that you want to receive the data, put this in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(yourSelector:)
name:#"addedData"
object:nil];
Then implement the method that receives that data:
- (void)yourSelector:(NSNotification *)notification {
Foo *foo;
foo = [notification object];
//do something else
}
Now in the class where the data is originated from, you post a notification that new data was created. Also, you pass along the data that you want to have the other method receive.
[[NSNotificationCenter defaultCenter] postNotificationName:#"addedData"
object:foo];
I've done this to send a value from one view controller to another, hope it helps
UITabBarViewController *var = [self.storyboard instantiateViewControllerWithIdentifier:#"name"]; //I select the UITabBarController
otherViewController *var2 = [var.childViewControllers objectAtIndex:0]; //I Select the first ViewController from that UITabBarController
var2.variable = #"value";
[self.navigationController pushViewController:var animated:YES];

Resources