Next button is not working. It throws an error Application tried to present modally an active controller What should i do to enumerate through array of ViewControllers when i press next button. I have read many threads regarding the same problem but could not figure out the solution. Thanks in advance!
.h file
#property(nonatomic, strong) NSMutableArray *tab;
.m file
- (IBAction)newTab:(id)sender {
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
myViewController *newTab = [st instantiateViewControllerWithIdentifier:#"myViewController"];
if (![newTab isBeingPresented]) {
[self presentViewController:newTab animated:YES completion:nil];
[tab addObject:newTab];
}
}
- (IBAction)next:(id)sender {
[tab enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[self presentViewController:tab[idx] animated:YES completion:nil];
}]; }
- (IBAction)prev:(id)sender {
for (i=[tab count]; i>0; i--) {
if (![self isBeingDismissed]){
[tab[i-1] dismissViewControllerAnimated:YES completion:nil];
;
}}}
You can enumerate the ViewControllers present in stack
NSArray * controllerArray = [[self navigationController] viewControllers];
for (UIViewController *controller in controllerArray){
//Code here.. e.g. print their titles to see the array setup;
NSLog(#"%#",controller.title);
if ([controller.title isEqual:#"Title1"]) {
[self.navigationController popToViewController:controller animated:YES];
}
}
On selecting Next button enumerate through the Views present in stack and check for the title and do that specific operation needed for that view. Above i have added the code to popViewController if the title matches.
Hope it helps.
Related
I'm adding a UIButton to a view on a different UIViewController. I need the target selector to point to that view controller from json value
- (IBAction)timeline:(id)sender {
if ([_NoTimeline isEqualToString:#"timeline not available :)"]) {
NearmeNOViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"NONearmeViewController"];
[self presentViewController:vc animated:YES completion:nil];
} else {
NearmeFrendViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"NearmeFrendViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
}
Here you are assigning NSString "timeline not available :)" to variable self.NoTimeline if timeline isnt available. And assigning an NSArray to variable self.NoTimeline. If you can edit your api add status key properly. If not try this
- (IBAction)timeline:(id)sender{
if ([self.NoTimeline isKindOfClass:[NSString class]]) {
NearmeNOViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"NONearmeViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
else {
NearmeFrendViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"NearmeFrendViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
}
The problem here seems to be that _NoTimeline is not always of type NSString. Therefore the isEqualToString: operation fails.
You can check for NSString by using:
if ([_NoTimeline isKindOfClass:[NSString class]] {
// Your code
}
I am making demo in which I have to remove some of viewControllers from the NavigationController, and for that I have implemented below code but it give me issue.
I have pushed VC1,VC2,VC3 and now I want to push VC4 and remove VC2...
ViewController4 *VC4=[[ViewController4 alloc]initWithNibName:#"ViewController4" bundle:nil];
[self.navigationController pushViewController:VC4 animated:YES];
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
for(UIViewController *objVC in viewControllers)
{
if([objVC isKindOfClass:[ViewController2 class]])
{
[viewControllers removeObjectIdenticalTo:objVC];
}
}
self.navigationController.viewControllers =viewControllers ;
This code works fine with iOS8 but in iOS7 with VC2 also VC3 removes automatically when I press the back button in VC4.
Even if I put below code the controller automatically removes from stack.
ViewController4 *VC4=[[ViewController4 alloc]initWithNibName:#"ViewController4" bundle:nil];
[self.navigationController pushViewController:VC4 animated:YES];
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
self.navigationController.viewControllers =viewControllers ;
Here is the fix, working fine in iOS7 and iOS8:
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
// Find the things to remove
NSMutableArray *toDelete = [NSMutableArray array];
for(UIViewController *objVC in viewControllers)
{
if([objVC isKindOfClass:[ViewController2 class]])
{
[toDelete addObject:objVC];
}
}
[viewControllers removeObjectsInArray:toDelete];
self.navigationController.viewControllers =viewControllers ;
ViewController4 *VC4=[[ViewController4 alloc]initWithNibName:#"ViewController4" bundle:nil];
[self.navigationController pushViewController:VC4 animated:YES];
In my application, I have 4 UIViewcontrollers - A, B, C and D.
From my UIViewController A, UIVIewControllers B or C or D can be presented. Suppose, from A, i have presented B. Then, on B, there is are two UIButtons, clicking on which, i need to dismiss B and Present C or dismiss B and Present D. This is happening successfully, but first, after dismissing B, the screen of A comes, and then it goes to C or D.
Here's what i did:
On Button Press On B, the action is:
{
UINavigationController *controller = (UINavigationController *)self.parentViewController;
NSLog(#"%#",[controller parentViewController]);
UITabBarController *tabBarReference = (UITabBarController *)[controller parentViewController];
HomePageViewController *presController = (HomePageViewController *)tabBarReference.presentingViewController;
[presController dismissTabControllerWithHandlerWithSenderAtIndex:1];
}
In A, i have these methods:
-(void)dismissTabControllerWithHandlerWithSenderAtIndex:(NSInteger)index
{
if(index == 0)
{
[self dismissViewControllerAnimated:NO completion:^{
[self aboutButtonPressed:self];
}];
}
else
{
[self dismissViewControllerAnimated:NO completion:^{
[self settingsButtonPressed:self];
}];
}
}
Here's the method i am calling..
- (IBAction)settingsButtonPressed:(id)sender
{
[self.contactUsView setHidden:YES];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *deviceType = [prefs objectForKey:#"DeviceType"];
NSString *iOSType = [prefs objectForKey:#"iOSType"];
if([iOSType isEqualToString:#"iOS7"])
{
if([deviceType isEqualToString:#"iPad"])
{
SettingsViewController *settingsPage = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController_iPad" bundle:NULL];
settingsPage.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:settingsPage animated:YES completion:NULL];
}
else
{
SettingsViewController *settingsPage = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:NULL];
settingsPage.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:settingsPage animated:YES completion:NULL];
}
}
else
{
if([deviceType isEqualToString:#"iPad"])
{
SettingsViewController *settingsPage = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController_iPad_iOS6" bundle:NULL];
settingsPage.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:settingsPage animated:YES completion:NULL];
}
else
{
SettingsViewController *settingsPage = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController_iOS6" bundle:NULL];
settingsPage.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:settingsPage animated:YES completion:NULL];
}
}
}
Ok here goes:-
Suppose viewcontroller A is the base & it presents either view controllers B or C.
Implement delegate/notifications where the view controller B or C has to be dismissed.
After sending the delegate or posting the notification, dismiss the current view controller without animation, i.e animation:NO.
This notification that was posted needs to be heard in view controller A.
Here you present the next view controller.
EDIT:-
-(void)dismissTabControllerWithHandlerWithSenderAtIndex:(NSInteger)index
{
if(index == 0)
{
[self dismissViewControllerAnimated:NO completion:nil];
[self aboutButtonPressed:self];
}
else
{
[self dismissViewControllerAnimated:NO completion:nil];
[self settingsButtonPressed:self];
}
}
I have implemented a delegate for the SKStoreProductViewController.
I add that view controller into the key window's view controller.
I have also implemented a dismiss view controller code in the delegate function.
The question seems to be answer in this question.
Modal App Store won't dismiss
Yet, this problem still persist in my situation.
Display function
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
NSString *appURL = [NSString stringWithFormat:#"itms-apps://itunes.apple.com/%#/app/id%#",
[[NSLocale preferredLanguages] objectAtIndex:0], applicationID];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:appURL]];
} else {
NSDictionary* dict = [NSDictionary dictionaryWithObject:applicationID forKey:SKStoreProductParameterITunesItemIdentifier];
SKStoreProductViewController *viewCont = [[SKStoreProductViewController alloc] init];
viewCont.delegate = self;
[viewCont loadProductWithParameters:dict completionBlock:^(BOOL result, NSError *error)
{
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
if (viewController)
{ [viewController presentViewController:viewCont animated:YES completion:nil]; }
}];
}
Delegate Function
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
if (viewController)
{ [viewController dismissViewControllerAnimated:YES completion:nil]; }
}
The problem is that you must implement
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
if (viewController)
{ [self dismissViewControllerAnimated:YES completion:nil]; }
}
inside the delegate class. If you implement it inside the class whose delegate is presenting the SKStoreProductViewController, it will not work because SKStoreProductViewController will try to call productViewControllerDidFinish: within it's delegate, which isn't implementing that method.
Let me show an example:
#implementation MainViewController
- (void)presentSecondViewController
{
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[secondViewController setDelegate:self];
[self presentViewController:secondViewController animated:YES completion:nil];
}
- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController
{
if (viewController)
{ [self dismissViewControllerAnimated:YES completion:nil]; }
}
#end
#implementation SecondViewController {
id delegate <SKStoreProductViewControllerDelegate>;
}
- (void)setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void)callStoreProductViewController
{
SKStoreProductViewController *viewCont = [[SKStoreProductViewController alloc] init];
viewCont.delegate = _delegate;
[viewCont loadProductWithParameters:dict completionBlock:^(BOOL result, NSError *error)
{
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
if (viewController)
{ [_delegate presentViewController:viewCont animated:YES completion:nil]; }
}];
}
#end
So, if I did understand your problem well, you must implement productViewControllerDidFinish: inside your viewController class, as it is the one who is presentig the SKStoreProductViewController.
Hope this helps!
Please try in Delegate function, replace all lines with:
[self dismissViewControllerAnimated:YES completion:nil];
Where does this code reside? You set the delegate to the instance where this code is written, but you are adding the SKStoreProductViewController to the root view.
Have you tried adding the store to self?
[self presentViewController:storeController animated:YES completion:nil];
Thanks for the delegate function. It isn't obvious in the documentation.
According to the documentation, instantiateViewControllerWithIdentifier "creates a new instance of the specified view controller each time you call it."
I'm running my app (using ARC) with Instruments' Activity Monitor, and I notice absolutely no difference in memory usage when I use to instantiate a ViewController that was instantiated before.
Why is that? See method goToPreviousPage below:
#implementation CBNavigator
int currentPage = 0;
-(IBAction)goToNextPage{
[self dismissViewControllerAnimated:YES completion:^{
currentPage++;
UIViewController *nextPageVC = [self.storyboard instantiateViewControllerWithIdentifier:[NSString stringWithFormat:#"%d", currentPage ]];
[self presentModalViewController:nextPageVC animated:YES];
}];
}
-(IBAction)goToPreviousPage{
[self dismissViewControllerAnimated:YES completion:^{
currentPage--;
UIViewController *previousPageVC = [self.storyboard instantiateViewControllerWithIdentifier:[NSString stringWithFormat:#"%d", currentPage ]];
[self presentModalViewController:previousPageVC animated:YES];
}];
}
#end