how can i push a view only once with in a method calling multiple times in iphone - iphone

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
ChatViewController *chatView;
if(contactView==nil)
{
chatView=[[ChatViewController alloc] initWithNibName:#"ChatViewController" bundle:nil];
}
[self.navigationController pushViewController:chatView animated:YES];
[messageDelegate newMessageReceived:m];
}
The above delegate method called for every incoming message.When it called, it goes to a new UIViewController.Here my problem is a view pushed multiple tinmes,so error will be occered.how can i fix this error in iphone

Add this snippet before pushing the view controller
BOOL viewControllerAlreadyPushed = NO;
for (UIViewController *controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[ChatViewController class]]) {
viewControllerAlreadyPushed = YES;
}
}
if(!viewControllerAlreadyPushed) //if not pushed, push it
{
ChatViewController *chatView;
if(contactView==nil)
{
chatView=[[ChatViewController alloc] initWithNibName:#"ChatViewController" bundle:nil];
}
[self.navigationController pushViewController:chatView animated:YES];
[messageDelegate newMessageReceived:m];
}

Related

iOS6 autorotation - UIPageViewController

My UI structure:
UINavigationController
--UIViewController(first)
|
|Modal
|
V
UINavigationController (subclass)
--UIViewController (contains UIPageViewController)
For iOS6 new autorotation, I created a subclass of UINavigationController and added:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Only want keep the orientation is portrait.
And I initialize UIPageViewController like:
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
PageDataViewController *startingViewController = [self viewControllerAtIndex:start storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
Then I perform the Modal segue,
if the first UIViewController is portrait, the pageViewController works,
but if the first UIViewController is landscape, I always got exception:
* Assertion failure in -[UIPageViewController willAnimateRotationToInterfaceOrientation:duration:],
/SourceCache/UIKit_Sim/UIKit-2372/UIPageViewController.m:945
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No view controllers'
** First throw call stack: (0x2a5e012 0x19bae7e 0x2a5de78 0x1450f35 0xd75974 0x9f12b4 0x9f13ea 0x9e4c32 0x9f1372 0x9f13ea 0x9e4c32
0x9f1372 0x9f1751 0x93a1a6 0xbee5f9 0x9ec4f3 0x9ec777 0x9ec7b7
0xd57fe2 0xd49ad9 0xd49b54 0x9b1899 0x9b1b3d 0x13b8e83 0x2a1d376
0x2a1ce06 0x2a04a82 0x2a03f44 0x2a03e1b 0x2c967e3 0x2c96668 0x90265c
0xea7d 0x2685 0x1) libc++abi.dylib: terminate called throwing an
exception
Actually There is another solution for it.
The rotation just calling the willAnimateRotationToInterfaceOrientation method to the rootViewController, you have to implement the method of it.
#interface UIPageViewController (Rotation)
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
#end
//Implementation file
#import "UIPageViewController+Rotation.h"
#implementation UIPageViewController(Rotation)
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {}
#end
In the documentation about "supportedInterfaceOrientations" it is written:
When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window
Did you try setting the rootViewController for the main windows to your current NavigationController classes?
Like in the AppDelegate:
self.window.rootViewController = nvc;
And when your navigationController is changing, set the rootViewController again...
I have "fixed" the problem, by setting view controllers to UIPageViewController in viewWillAppear: again, because when this method is called, spine location for page view controller is correct and based on this information i set one, or two pages (view controllers)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(self.pageViewController.spineLocation == UIPageViewControllerSpineLocationMid)
{
BookPageViewController *currentViewController = self.pageViewController.viewControllers[0];
NSArray *viewControllers = nil;
NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController];
if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
viewControllers = #[currentViewController, nextViewController];
} else {
UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
viewControllers = #[previousViewController, currentViewController];
}
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
}
if(self.pageViewController.spineLocation == UIPageViewControllerSpineLocationMin)
{
[self.pageViewController setViewControllers:[NSArray arrayWithObject:[self.pageViewController.viewControllers objectAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
}
}
and set UIPageViewController Delegate method as below
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
BookPageViewController *currentViewController = self.pageViewController.viewControllers[0];
if(UIInterfaceOrientationIsPortrait(orientation))
{
[self.pageViewController setViewControllers:[NSArray arrayWithObject:currentViewController] direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMin;
}
if(UIInterfaceOrientationIsLandscape(orientation))
{
NSArray *viewControllers = nil;
NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController];
if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
viewControllers = #[currentViewController, nextViewController];
} else {
UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
viewControllers = #[previousViewController, currentViewController];
}
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward | UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
return UIPageViewControllerSpineLocationMid;
}
return UIPageViewControllerSpineLocationMin;
}
I have "fixed" the problem, by setting view controllers to UIPageViewController in viewWillAppear: again, because when this method is called, spine location for page view controller is correct and based on this information i set one, or two pages (view controllers)

MBProgressHud not hiding after second look

I have a MBProgressHUD that I want to display when switching tabs. This is in my app delegate. I have this code here to display the HUD on only the first three tabs
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if ([viewController isKindOfClass:[UINavigationController class]]) {
if (tabBarController.selectedIndex >= 3) {
UINavigationController *nav = (UINavigationController *) viewController;
[nav popToRootViewControllerAnimated:NO];
}
else {
UINavigationController *nav = (UINavigationController *) viewController;
HUD = [[MBProgressHUD alloc] initWithView:nav.view];
[nav.view addSubview:HUD];
HUD.labelText = #"Loading";
[HUD show:YES];
[nav popToRootViewControllerAnimated:NO];
}
}
}
The first time I view my page it works but going back to it a second time it doesn't hide. I have my [appDel.HUD hide:YES afterDelay:1.0]; in my viewDidAppear.
How can I get the HUD to hide every time I visit the page?
I think you may be adding the MBProgressHUD to a different view within the UINavigationController. Then you're popping to the root, and it's trying to remove an MBProgressHUD that doesn't exist. Try this (untested code)...
UINavigationController *nav = (UINavigationController *) viewController;
[nav popToRootViewControllerAnimated:NO];
if(![nav.visibleViewController.view.subViews containsObject:MBProgressHUD])
{
[MBProgressHUD showHUDAddedTo:nav.visibleViewController.view animated:YES];
MBProgressHUD.labelText = #"Loading";
}
else
{
[MBProgressHUD setHidden:NO];
}
you have to check if the MBProgressHUD view was already activated if so hid it, or simply do so:
if (!HUD) {
[self showLoadingHUD];
}

Calling a viewcontroller another class from connectiondidfinish delegate NSURLConnection

Trying to launch a viewcontroller in connectiondidfinish delegate method of NSUrlConection
//Sprequest.m inherited from nsobject
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
NSLog(#"connectionDidFinishLoading ");
if(nStatus == 401)
{
NSLog(#"called maincontroller to launch dvrview");
MainController *mainview =[[MainController alloc] init];
[mainview reponseFromServer];
}
}
//maincontroller.m from viewcontroller
-(void)reponseFromServer
{
NSLog(#"response from server - main controller ");
dvrView *dvrObj = [[dvrView alloc]initWithNibName:#"dvrView" bundle:nil];
[self.navigationController pushViewController:dvrObj animated:YES];
}
this dvr view doesnt get loaded
Sprequest.m is inherited from NSObject , its not a viewController subclass so you cant use
[self.navigationController pushViewController:dvrObj animated:YES];
inside Sprequest.m
You can get the navigationController object from the appdelegate like this
((AppDelegate *)[UIApplication sharedApplication].delegate).navigationController
then use
[((AppDelegate *)[UIApplication sharedApplication].delegate).navigationController pushViewController:dvrObj animated:YES];

dismissing modalViewController of modalViewController

So I have a UITabBarController app and I want to display a login page, and so I did:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(userDidLogin:) name:UserDidLoginNotification object:nil];
LoginViewController* loginViewController = [[LoginViewController alloc] init];
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
[self.tabBarController.selectedViewController presentModalViewController:loginViewController animated:NO];
[loginViewController release];
Inside my LoginViewController I can as well show another modalViewController:
- (void) twitterLogin: (UIViewController *) askingView
{
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _twitter delegate: self];
if (controller) {
self.askingView = askingView;
[askingView presentModalViewController: controller animated: YES];
}
}
I have the following method where the askingView is the LoginViewController,
when I want to dismiss this I do:
[self.askingView dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:UserDidLoginNotification object:nil];
However, this doesn't dismiss the LoginViewController and show the UITabBarController views.. it just dismisses my modalViewController shown from the LoginvVIewController. What am I doing wrong here? I am also getting the following error:
attempt to dismiss modal view controller whose view does not currently appear. self = <LoginViewController: 0x2aff70> modalViewController = <SA_OAuthTwitterController: 0x2d2a80>
2011-09-16 09:45:37.750 VoteBooth[4614:707] attempt to dismiss modal view controller whose view does not currently appear. self = <MainViewController: 0x29fec0> modalViewController = <LoginViewController: 0x2aff70>
In order to dismiss a modal view that is presented over another modal view, you have to call dismissModalViewControllerAnimated: on the parent of the parent. I have used this in some of my apps and it has worked beautifully for me (after many painstaking hours trying to figure it out). Here is exactly what I've used:
[[[self parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];
if ([self respondsToSelector:#selector(presentingViewController)]) {
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES]; // for IOS 5+
} else {
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES]; // for pre IOS 5
}
If you have a dynamic UX and do not know how many parents to go to, you can use this recursive function to figure it out...
- (void) goHome
{
//Dismiss modal back to home page
int numberOfVcsToDismiss = [self findRootViewController:self];
[self dismissToRootVc:numberOfVcsToDismiss];
}
- (int) findRootViewController:(UIViewController*)vc
{
if(vc)
{
return 1 + [self findRootViewController:vc.presentingViewController];
}
return 0;
}
- (void) dismissToRootVc:(int)count
{
if(count == 1)
[self dismissViewControllerAnimated:YES completion:^{}];
if(count == 2)
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 3)
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 4)
[self.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 5)
[self.presentingViewController.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
//etc....
}

Modal View Not Working

I am using the following code in my view controller and I want it to present another view controller called "chooserViewController" modaly
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
{
[self presentModalViewController:chooserViewController animated:YES];
}
I am getting a compile error not recognizing "chooserViewController". Am I doing it wrong?
Update:
- (void)add:(id)sender
{
RoutineExerciseChooserViewController *routineExerciseChooserViewController = [[RoutineExerciseChooserViewController alloc] initWithNibName:#"RoutineExerciseChooserViewController" bundle: nil];
[self presentModalViewController:routineExerciseChooserViewController animated:YES];
[routineExerciseChooserViewController release];
}
You need to create chooserViewController:
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated {
ChooserViewController *chooserViewController = [[ChooserViewController alloc] initWithNibName:#"ChooserView" bundle: nil];
[self presentModalViewController:chooserViewController animated:YES];
[chooserViewController release];
}
If you're not loading from a nib, obviously you'll use a different way to create chooserViewController, but you have to do something to ensure it exists, and can then be presented.