iOS using navigationController popToRootViewControllerAnimated - objective-c

When I try to use popToRootViewControllerAnimated method my screen turns black.
I think I really get back to the expected view though because if I rotate my device to landscape the view appears correctly.
Here is the context of my application:
A viewcontroller A is nested into a navigation controller. Clicking on a button triggers a segue to viewcontroller B. In the viewDidLoad method of viewcontroller B a connection helper is created in order to collect some data on our server database. While being created the helper is checking if the device is connected to internet. If it's not then "popToRootViewControllerAnimated" is called to return to viewcontroller A.
Here is the code of the helper:
+(AFHTTPClient*) getClient {
if (!client) {
[self createClient];
}
if (client.networkReachabilityStatus <AFNetworkReachabilityStatusReachableViaWWAN) {
[currentController.navigationController popToRootViewControllerAnimated:YES];
//[[[UIAlertView alloc] initWithTitle:#"Connection Problem" message:#"You don't seem to be connected to internet. Please enable WI-Fi or 3G then try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil] show];
client = nil;
}
return client;
}
+(void) createClient{
NSURL* baseUrl = [NSURL URLWithString:[[#"http://" stringByAppendingString:[ApplicationTask GetApiUrl]] stringByAppendingString:#"/"]];
client = [AFHTTPClient clientWithBaseURL:baseUrl];
client.parameterEncoding = AFJSONParameterEncoding;
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client setDefaultHeader:#"Content-Type" value:#"application/json"];
}
Once the "popToRootViewControllerAnimated" method as been called, I can see the view from controller A sliding and a black screen is showing up.
As I mentioned earlier it feels like I am brought back to viewcontroller A (rotating the device from portrait to landscape orientation show the view) but the view seems like outside the frame of the screen.
Hope I made everything clear.
Thanks

As I mentioned into my comment, popping to the root controller in the viewDidAppear method seem to do the trick.

Related

Displaying a subView in didReceiveRemoteNotification?

What Im trying to do is displaying my subView in didReceiveRemoteNotification when the app receives a notification and is running. How can I do this?
My code right now in didReceiveRemoteNotification:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
//Here I try to get the current viewController running...
UIViewController *viewController = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
//This line gives me the "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView view]: unrecognized selector sent to instance 0x17816b7c0" error
[viewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:viewController andText:[[userInfo objectForKey:#"aps"] objectForKey:#"message"]]];
}
else
{
//other things
}
My AcceptAlertViewCreator returns a UIView and gets a viewController for the viewController to be displayed in and NSString for message. My AcceptAlertViewCreator also has a UIViewAnimation when it is played.
My AcceptAlertViewCreator works great when added to a normal ViewController subView.
Anyone knows how I can accomplish this? Id doesn't have to be adding a subView. It could be a workaround in some ways, or please give me some pointers. Thanks
Instead of getting the viewController from sharedApplication just get the rootViewController of you window
You didReceiveRemoteNotification method should look like this:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
[self.window.rootViewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:self.window.rootViewController andText:[NSString stringWithFormat:#"%#", [[userInfo objectForKey:#"aps"] objectForKey:#"message"]]]];
}
else
{
//other things
}
So you are having your AppDelegate display a window when an alert comes in.
I would not add it as a subview, I would just present the view controller instead. I assume you want some action to be taken when this notice comes in.
You could also use NSNotificationCenter to send a notification to your app when the push notification comes in. You trigger the NSNotification from didReceiveRemoteNotification and your app views would need to listen for this notifications. The downside is each view would need to listen for this notification.

Xcode - I can't run the whole methods from AppDelegate

I'm using custom URL schemes to open my app, then get the link and run in a method. But I can't really run the method.
For example, I can't load web views or change labels or text fields. So how do I load web views and change labels?
AppDelegate.m:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if (!url) { return NO; }
NSString *URLopen= [[url host] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
ViewController *vc = [[ViewController alloc]init];
vc.URLschemeLink = URLopen;
[vc URLscheme];
return YES;
}
ViewController.h:
#interface ViewController : UIViewController<MFMailComposeViewControllerDelegate> {
NSString *URLschemeLink;
}
-(void)URLscheme;
#end
ViewController.m:
#implementation ViewController
#synthesize URLschemeLink;
-(void)URLscheme {
//for example:
label.text = #"Hello"; //nothing will happen
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]]]; //Nothing will happen
NSLog ("Method Works Perfect"); //will happen
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Title:"
message:[NSString stringWithFormat:#"%#", URLSchemeLink]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
//UIAlertView will work perfectly and show the URLschemeLink from AppDelegate.
}
ok How to load the label/webview anyway?
i tested to pass a bool named runURLscheme (=true) from app delegate.
then i wrote in ViewDidLoad:
if(runURLscheme==true) {
[self URLScheme];
}
but this will not work, it will not run the URLscheme method.
How can i load the labels/webviews anyway?
The main views associated with view controllers are generally lazy loaded. Just because the view controller is initialised, it doesn't mean it's loaded its main view yet. Your views are only safe to access once viewDidLoad has been called.
Generally speaking, this pattern works well:
Store your data independently of any views that display it.
When your custom URL scheme runs, update this data.
Have a method on your view controller that updates its views from this data.
Call this method from viewDidLoad.
If there's a chance this data will be updated after your views have already been loaded (e.g. if you are receiving data from the network), then use notifications or KVO to call your view updating method again.

Login View in tabbed application

How can I build a login view in a tabbed application? I'm new in ios development. I have read a lot through the internet but no one just posts the code I can understand. Any help is appreciated =).
here is a related post here: Adding login screen in front of Cocoa Touch Tab Bar Application for IOS
I prefer writing like this tho.
[window setRootController:tabBarCon];
if (notLogedIn) {
loginViewController = [[InitialScreenViewController alloc] init];
[tabBarCon.view addSubview:loginViewController.view];
}
[window makeKeyAndVisible];
return YES;
- (bool)notLoggedIn {
//check if there is any sessions exists in local storage
}
If your content relates to the user account, remember to implement a method to reload the the content after login.
Finally I did This to solve my question:
My rootViewController is my registration view, then I set a button with implements a custom segue:
-(IBAction)button {
NSLog(#"username: %#, password: %#, passwordrt: %#", username.text, password.text, passwordrt.text);
[self performSegueWithIdentifier:#"tabBar" sender:self];
}

Presenting a Modal View Controller hides the Navigation Bar

I have a navigation based app with a navigation bar, but there are a few instances where instead of pushing a view controller onto the stack, I need to present the view controller modally. The problem is that when I dismiss the modal view controller, everything functions as expected except that the navigation bar is hidden and the (parent view) has been resized, which is the expected behavior according to the docs. So I figured I could simply call a built-in method to unhide the navigation bar. I have already tried
[self.navigationController setNavigationBarHidden:NO];
as well as the animated version without success.
The documentation talks about this in the method
presentModalViewController: animated:
in the discussion section where it says,
On iPhone and iPod touch devices, the view of modalViewController is always presented full screen" and "Sets the modalViewController property to the specified view controller. Resizes its view and attaches it to the view hierarchy."However, the docs didn't clue me in as to how to undo this process after dismissing a modal view.
Has anyone else experienced this and found a solution?
Edit: I am having this same problem, so instead of asking my own question I am sponsoring a bounty on this one. This is my specific situation:
In my case, I am presenting an Image Picker in a Modal View Controller, over a Navigation Controller:
-(void) chooseImage {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
imagepicker = [[UIImagePickerController alloc] init];
imagepicker.allowsEditing = NO;
imagepicker.delegate = self;
imagepicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagepicker.navigationBar.opaque = true;
imagepicker.wantsFullScreenLayout = NO;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if (self.view.window != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:imagepicker];
[popoverController presentPopoverFromBarButtonItem:reset permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
} else {}
} else {
[self.navigationController presentModalViewController:imagepicker animated:YES];
}
}
}
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.popoverController dismissPopoverAnimated:true];
} else {
[self.navigationController dismissModalViewControllerAnimated:YES];
}
//Save the image
}
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self.popoverController dismissPopoverAnimated:true];
} else {
[self.navigationController dismissModalViewControllerAnimated:YES];
}
}
Make sure you a presenting AND dismissing the modalViewController from the UINavigationController, like so:
// show
[self.navigationController presentModalViewController:vc animated:YES];
// dismiss
[self.navigationController dismissModalViewControllerAnimated:YES];
If your view controller is actually on the UINavigationController's stack then this is the correct way to handle the presentation and dismissal of the modal view controller. If your UINavigationBar is still hidden, there is something else funky going on and we would need to see your code to determine what is happening.
Edit
I copied your code into an app of mine and the UIImagePickerController successfully presented and dismissed and my UINavigationController's UINavigationBar was still there. I truly believe that the problem lays elsewhere in your architecture. If you upload a zip w/ an example project I will take a look.
Simply try following code it will work
SettingsViewController *settings = [[SettingsViewController alloc] init];
UINavigationController *navcont = [[UINavigationController alloc] initWithRootViewController:settings];
[self presentModalViewController:navcont animated:YES];
[settings release];
[navcont release];
One need to present the navigation controller in order to have navigation bar on the presented controller
I think I've seen this behavior when presenting a view controller on the wrong VC. Are you calling presentModalViewController on the navigation controller or the individual VC?
Try calling it from the navigationController if you aren't already.
[self.navigationController presentModalViewController:myVC animated:YES];
If you present a controller as model, View controller will appear to total view.
If you want to access the navigation controller properties over the model view, You need to create another navigation controller reference and it continues as previous.
This may be useful for you.
Check this out. This is Apple's Documentation under UIViewController Class Reference:
It clearly mentions that modal view always presents in full screen mode, so it is obvious that navigation bar will be hidden. So put the seperate navigation bar on modal view to navigate back.
presentModalViewController:animated:
Presents a modal view managed by the given view controller to the user.
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
Parameters
modalViewController
The view controller that manages the modal view.
animated
If YES, animates the view as it’s presented; otherwise, does not.
Discussion
On iPhone and iPod touch devices, the view of modalViewController is always presented full screen. On iPad, the presentation depends on the value in the modalPresentationStyle property.
Sets the modalViewController property to the specified view controller. Resizes its view and attaches it to the view hierarchy. The view is animated according to the transition style specified in the modalTransitionStyle property of the controller in the modalViewController parameter.
Availability
Available in iOS 2.0 and later.
Hope this helps you understand that hiding the whole view along with navigation controller is default behaviour for modal view so try putting a seperate navigation bar in modal view to navigate.
You can check it further on this link
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
AddContactVC *addController =[self.storyboard instantiateViewControllerWithIdentifier:#"AddContactVC"];
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:addController];
[self presentViewController:navigationController animated:YES completion: nil];
working for me shows navigation bar
Emphatic and Devin –
As I started reading through the Apple docs to get familiar with the problem, I noticed that the method you're using, presentModalViewController:animated:, appears to be deprecated in favor of presentViewController:animated:completion:. Perhaps you should try to use that method instead.
For your convenience, take a look for yourself:
presentModalViewController:animated: reference
I'll try to put together a quick test program to see whether what I've said above is actually true. But give it a shot – maybe it'll help!
Xcode has a template that does pretty close to what you're doing. from the results, i don't think you should be attempting to perform [self.navigationController presentModalViewController:vc] and [self.navigationController dismissModalViewControllerAnimated:] , but rather simply [self presentModalViewController:] and [self dismissModalViewControllerAnimated:] .
to see how the template does this for yourself, you can use the new project wizard in xcode 4.3 . perhaps it will provide some guidance:
from that choice, choose Next, then give your test project a name, choose "Universal", turn off automatic reference counting, hit next, save where you want it.
now, click on the target and switch the deployment target to 4.3 (or 4.0 if you prefer) for your testing purposes, and switch to your device or the iOS 4.3 simulator .
finally, substitute the following code in applicationDidFinishLaunching:withOptions: in the created AppDelegate.m:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.mainViewController = [[[MainViewController alloc] initWithNibName:#"MainViewController_iPhone"
bundle:nil] autorelease];
} else {
self.mainViewController = [[[MainViewController alloc] initWithNibName:#"MainViewController_iPad"
bundle:nil] autorelease];
}
UINavigationController* navigationController
= [[UINavigationController alloc] initWithRootViewController:self.mainViewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
now, when i run this, it doesn't hide the navigationBar. and in the created MainViewController.m from the template, you'll see how it presents the modal view controller and dismisses it from the controller itself and not from the navigation controller. for good measure, to make the template code more like your own, go into MainViewController.m and delete the line that sets the modal view controller transition style ...
(of course, in iOS 5, with storyboards, the same thing can all be accomplished with modal segues ... which is how i've done this for apps that i'm not supporting for pre-5.0 that present a modalViewController in this fashion.)
One of the best solution it to use this Category MaryPopin
https://github.com/Backelite/MaryPopin

Create a UINavigationBar without using [Projectname]AppDelegate?

I'm trying to create another UINavigationBar in my project, but it seems that I'm missing some key detail. When the application first loads, it does have it's own navigation system, but now I'm trying to add another navigation to a modal.
Many tutorials show you need to connect the view to the [self window], which only seems to work in the AppDelegate files, but when I've tried placing the code* in viewDidLoad, I can never seem to build without any errors.
I've seen this in multiple apps, but how is this done (programmatically or with IBuilder)?
Thanks!
Example code I've tried in viewDidLoad
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[self viewController]];
[self.window addSubview:navigationController.view];
You don't show enough code to be able to understand how you do it, but it seems to me that you are showing a controller modally, then trying to add as a subview to its view a navigation controller.
You can try and directly push modally your navigation controller (from your app delegate or where it makes sense for your app):
(IBAction) navigateToSecondaryViewController {
if (secondaryViewController == nil) {
informationTableViewController = [[SecondaryViewController alloc]
initWithNibName:#"SecondaryViewController"
bundle:[NSBundle mainBundle]];
secondaryViewController.delegate = self;
}
if (navController == nil) {
navController = [[UINavigationController alloc]
initWithRootViewController:secondaryViewController];
}
[self presentModalViewController:navController animated:YES];
}
Full example here.