How to dismiss and push new ViewController - ios

In my application there is a floating button. Its function is to open available screens from anywhere.
Scenario
Suppose I have 4 screens and in each screen their is floating Button.
1. Home Screen
2. Services Screen
3. Contact Screen
4. Events
Now suppose I have opened all screens. And currently I am in Contact Screen and I want to go to Services.
Then I have to push services again thus creating the object of Services Screen. This creates a problem as if the user gooes 10 times to Services then 10 new objects will be created.
How can I implement this scenario ?
My Code:
if([sender tag]==1)
{
[push home];
}
else if([sender tag]==2)
{
[push services];
}
else if([sender tag]==3)
{
[push Contact];
}
else
{
[push events];
}

I prefer to use UITabBarController.

Try with this.
UIViewController *popViewController = //assign here Services Screen or what view you want to back
BOOL isExist = NO;
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isEqual:popViewController]) {
isExist = YES;//exist view controller. so you should not create a new one
[self.navigationController popViewControllerAnimated:YES];
}
}
if (isExist==NO) {//not exist view controller. so you should create a new one
[self.navigationController pushViewController:YourViewController animated:YES];
}

#NSUser, sorry for not answering your exact problem, but I would recommend using UIPageViewController for "hosting" and presenting your content view controllers one at a time. Here is a conceptual document from Apple with essential description and how-to's. Good luck.

Related

Loading a view from a 3D Touch Quick Action

I'm adding dynamic 3D touch quick actions to my iOS app.
I was able to setup the code that displays each action, but I am having trouble finding what code would go within the code below. When the action is chosen, I need the action to open up one of 4 different view controllers within my app.
if ([shortcutItem.type isEqualToString:#"addOpportunity"]) {
} else if ([shortcutItem.type isEqualToString:#"bookMark"]) {
} else if ([shortcutItem.type isEqualToString:#"searchGuest"]) {
} else if ([shortcutItem.type isEqualToString:#"myGuest"]) {
}
else {
}
}
First you will have to create the instances of the view controllers that you intend to show in each of the if conditions.
For example:-
SearchGuestViewController * vc = [[SearchGuestViewController alloc] init];
Next you can present the view controller modally by doing the following:-
[self presentViewController:vc animated:YES completion:nil];
Note: You can only present a view controller from within another view controller.
This is one way of launching a view controller.
Read more about launching view controllers in the link below.
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html

Get the current view controller in ios

In my iPod device, I have attached an external device for scanning purpose. There is a scan button for the external device. The delegate methods for the scanner are in the view controller 'ScannerViewController'. Now I am in another view controller called 'NotificationViewController' and click the button present in the external device. When I click the button and the scan is complete, it triggers a method in the ScannerViewController. In that method, I need to get the name of the current view controller that is visible. That is in this case, I need to get the name of the view controller as NotificationViewController.
Have you tried this?.
NSLog(#"Current View Class: %#", NSStringFromClass(self.class));
If you are using navigation controller, you can try the following:
[self.navigationController topViewController];
to get the currently visible view.
Look at this
+ (UIViewController*) getTopController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
http://www.iosrocketsurgery.com/2013/07/get-current-viewcontroller-in-ios.html
Let's try this method
NSLog(#"Class name :%#", NSStringFromClass([self.presentedViewController class]);)

UINavigationController: presenting view controller while dismissing another controller is in progress on iPad

I have a view that requires user to be logged in. When the user attempts to open that view an he is not logged in I will call the login view for him to login and after he is done I will call the original view that he intended to see.
On iPhone this works fine as I push view controllers there.
But on iPad where I present view controller this does not work. It says that dismissal in progress, can't show new controller. Here is the code:
- (void) buttonPressed
{
if (!userLoggedIn) { // userLoggedIn getter calls new screens of login if needed
return; // this is executed if user declined to login
}
MyViewController *temp = [[MyViewController alloc] init];
[self.navigationController presentViewController:temp animated:YES]; // this returns warning that dismissal in progress and does not work
}
What can I do about that? On iPhone all of my logic works fine, but on iPad it fails. I use it in many places and completely rewriting code is not good.
EDIT: more code:
- (BOOL) userLoggedIn {
// code omitted
[centerController presentViewController:navController animated:YES completion:nil];
// code omitted
[centerController dismissViewController:navController animated:YES]; // setting to NO does not fix my problem
return YES;
}
EDIT2:
This is the code for iPad. I have removed iPhone-related code. What it does on iPhone - instead of presenting controller it uses pushing, and in that situation everything works fine.
You cannot present another view as long as the dismissing of your 1st view is not complete. The animation of dismissing view should be completed before presenting new view. So, either you can set its animation to NO while dismissing, or use
performSelector:withObject:afterDelay:
and present the next view after 2-3 seconds.
Hope this helps.
You've not posted enough code to really see what you're doing, but one approach to the problem of dismissing and pushing view controllers clashing in this way is to make a the pop+posh into a single atomic operation operation, rather then seqential operations.
You can do this by using the setViewControllers:animated: method on UINavigationController. This allows you to effectively remove one or more view controllers, and add one or more view controllers, all as one cohesive operation, with one seamless animation.
Here's a simple example:
[self.navigationController pushViewController:loginController];
// ... later on, when user login is validated:
NSMutableArray *viewControllers =
[self.navigationController.viewControllers copy];
[viewControllers removeLastObject];
[viewControllers addObject:[[MyNewViewController alloc] init]];
[self.navigationController setViewControllers:viewControllers animated:YES];
If you do things this way, your code will be more predictable, and will work across iPhone and iPad.
For more info, see the API docs.
Update
Since your problem involves a modal dialog on top, try using setViewControllers:animated:NO to change the nav controller stack underneath the modal login dialog before you dismiss the modal.

load UIViewController view over singleViewController style app

I have created a single view based application. I was wanting to overlay UIViewControllers as I needed them, for instance like a modal view thing where if some values are populated then load the next view until you do something there and you can come back.
This is the code I have
- (void) viewWillAppear:(BOOL)animated {
NSMutableDictionary *tempPrefs = [prefsController readPrefs];
NSString *tempName = [tempPrefs objectForKey:#"Name"];
NSString *tempProduct = [tempPrefs objectForKey:#"Product"];
// usedbefore so skip first view (first view == login view
if ((tempName.length != 0) && (tempProduct.length != 0)) {
// you have values, enter new room without checking
[self loadGetProListViewController];
}
}
- (void) loadGetProListViewController {
[self dismissViewControllerAnimated:NO completion:nil];
getProListViewController = [[GetProListViewController alloc] initWithNibName:#"GetProListViewController" bundle:nil];
[self presentViewController:getProListViewController animated:YES completion:nil];
}
However once this method has been reached its executed but nothing is happening..
If anyone could tell me how to create modal viewControllers or some description that would be greatly appreciated.
First you should be aware of UIViewController lifecycle to have an idea where you are able to present different UIViewController
Also I guess you have a bit incorrect architecture (maybe I wrong).
Let's imagine you have firstViewController on which -viewDidAppear method you present getProListViewController
Don't you think that presenting intermediate firstViewController is odd?
I'd reather you would move your if clause to level up. F.e:
/ usedbefore so skip first view (first view == login view
if ((tempName.length != 0) && (tempProduct.length != 0)) {
// present your getProListViewController
} else {
// present your "FirstViewController" (login or whatever)
}
And you haven't faced with your issue at the beginning
Try this
[self presentModalViewController: getProListViewController animated:YES];
instead of your presentviewcontroller
[self presentViewController:getProListViewController animated:YES completion:nil];

iOS Tabs speaking to each other

I have an app where there are two basic functions, delineated by being on separate tabs on a UITabBarController. Each tab has a particular button that when pressed should, as a separate function to its normal activity, also asynchronously tell the other tab to nil its data. How can I access one tab from the other?
This would be a good use for notifications (as in NSNotification, not local or push notifications).
You should have some sort of model for each view controller in each tab. Each model can publish its notification while registering for the other. This way, neither view controller or model needs to actually know about the other directly.
When the user taps a button, the view controller tells its model to publish its notification. The other one will get the notification and act accordingly.
See the docs for NSNotificationCenter and NSNotification for details.
Definition of "tabs" for UITabBarController
// define controllers for each tab
UIViewController *viewController1 = [[UIViewController alloc] init];
UIViewController *viewController2 = [[UIViewController alloc] init];
// define tab bar controller, "self" is a UITabBarController
self.viewControllers = [NSArray arrayWithObjects: viewController1, viewController2, nil];
From this point, if you need to access a particular tab, you want to do so via the "viewController1" or "viewController2" objects. Each of these UIViewController objects would presumably have access to certain data in your application.
You can access each of your viewControllers from TabBarController's viewControllers property, and iterate through them. Zero all but the live one (self).
Put it into a GCD dispatch queue for asynchronicity.
- (IBAction)pushButton:(id)sender {
NSLog (#"%# %#",self,NSStringFromSelector(_cmd));
//do normal stuff here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (id viewController in [[self tabBarController] viewControllers]) {
if ((viewController != self)
&& ([viewController respondsToSelector:#selector(zeroData)])) {
[viewController performSelector:#selector(zeroData)];
}
}
});
}
- (void) zeroData
{
NSLog (#"%# %#",self,NSStringFromSelector(_cmd));
//each view controller should zero out it's own data
//in a method called "zeroData"
}
If you try this and look at the logs, you will see that it leaves the current vc alone but sends zeroData to the others...
Are your tabs core-data driven? If you use a NSFetchedResultsController then you get notifications for free through the NSFetchedResultsControllerDelegate protocol. Otherwise, NSNotification like rmaddy suggests.

Resources