there's an alert in my app and when the user clicks on its ok-button an new few opens: But this few keeps empty...no buttons, etc. are shown (somehow the background is correctly shown).
This alert opens at first launch of the app in AppDelegate.m file:
-(void) alertView:(UIAlertView *) alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FirstVC *launchViewController = [[FirstVC alloc] init];
self.window.rootViewController = launchViewController;
[self.window makeKeyAndVisible];
}
}
Maybe it's wrong to use UIWindow.
Thanks to all of your answers. (FirstVC is the viewController shown after the alert-buttton is clicked)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:#"notFL"]) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle: #"Welcome"
message: #"..."
delegate: self
cancelButtonTitle:nil
otherButtonTitles:#"OK",nil];
[alert show];
[defaults setBool:YES forKey:#"notFL"];
}
}
You need to describe what controllers you have in the storyboard. What controller is the alert shown over when the app first opens? Your problem is that you're just alloc init'ing a FirstVC, not getting the one you set up in the storyboard. To get that instance, you need to do something like this:
FirstVC *launchViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstVC"];
This will work if you call it from the initial view controller that the alert is shown over. I think it would be better to put the coed you posted in the viewDidAppear method of that first controller.
If you want to do this in the app delegate, then you need to get a reference to the storyboard in a different way:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
FirstVC *launchViewController = [storyboard instantiateViewControllerWithIdentifier:#"FirstVC"];
Related
i'm developing an app in Objective-C with Xcode 7 for iOS 9 compatible devices, and I'm finding some difficulty in the login section. How should my storyboard be to show the login view controller as root view if the user is not already logged in?
In this app, the root view controller is a simple view controller with a segue to a navigation controller that holds two simple view controllers.
The way that I handle login is to have the login view controller embedded in a navigation controller. It is the initial view controller shown when the app runs.
I set a BOOL variable in NSUserDefaults called LoggedIn and check it every time the app is opened in viewDidLoad of the login view controller. If the variable = NO show the login view controller, and if the variable = YES push to the next view controller (animated:NO) so the first thing the user sees is the screen you want them on.
In your login view controller viewDidLoad:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([[defaults valueForKey:#"LoggedIn"] isEqualToString:#"YES"]) {
ViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"viewController"];
[self presentViewController:vc animated:NO completion:nil];
}
Set a Bool to NSUserdefaults after a login was successful. Put this Code in your method which is called after a successful login:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
defaults setBool:YES forKey:#"login.state"];
[defaults synchronize];
// go to your next ViewController
Then check in your Appdelegate.m in the didFinishLaunchWithOptions method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([defaults boolForKey:#"login.state"] == YES) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SWRevealViewController *swrvc = [storyboard instantiateViewControllerWithIdentifier:#"revealVC"];
self.window.rootViewController = swrvc;
[self.window.rootViewController.navigationController popViewControllerAnimated:YES];
}
else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
LoginViewController *lvc = [storyboard instantiateViewControllerWithIdentifier:#"loginVC"];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:lvc];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
}
}
If you need any help please ask!
Using NSUserDefaults, I'm able to present one view if it is the first launch and then another view if it isn't. My problem is, no matter what, the program thinks its the first launch. My code is as follows (in my AppDelegate.m file):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen ]bounds]];
NSString *storyboardID;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
bool hasLaunched = [defaults boolForKey:#"hasLaunched"];
if (!hasLaunched) {
storyboardID = #"firstLaunch";
hasLaunched = YES;
[defaults synchronize];
}
else {
storyboardID = #"notFirstLaunch";
}
UIStoryboard *main = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController = [main instantiateViewControllerWithIdentifier:storyboardID];
UINavigationController * navControl = [[UINavigationController alloc]initWithRootViewController:viewController];
self.window.rootViewController = navControl;
[self.window makeKeyAndVisible];
return YES;
}
I'm creating a nav controller programmatically. Another strange thing is that the first launch view controller (which always shows up) has a transparent nav bar over it. However, when I push to a different view controller (by presenting it), the second view controller doesn't have a nav bar over the top. I'm not sure why this would be the case, considering I'm moving the nav controller over to a new view controller.
You are setting the local variable hasLaunched to YES, but you are not storing this variable in NSUserDefaults -
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
bool hasLaunched = [defaults boolForKey:#"hasLaunched"];
if (!hasLaunched) {
storyboardID = #"firstLaunch";
[defaults setBool:YES forKey:#"hasLaunched"];
}
else {
storyboardID = #"notFirstLaunch";
}
I don't really understand your second question. I suggest you ask another question and include screen shots of your issue.
I am making an app. In which First User have to sign In then He allowed to use the app.
After successful login I want the user to directly switch to my HomeViewController.
Here is my code tho change navigation root view but it is not working
TermsConditionsController *firstViewController = [[TermsConditionsController alloc]init];
FirstPage *secondViewController = [[FirstPage alloc]init];
firstViewController.navigationController.viewControllers = [NSArray arrayWithObject: secondViewController];
FirstPage *nextScr = (FirstPage *) [self.storyboard instantiateViewControllerWithIdentifier:#"FirstPage"];
[self.navigationController pushViewController:nextScr animated:YES];
Connect your LoginViewController with HomeViewController by using segue.
give the identifier for the segue for ex name:successLogin.
and use this method:
[self performSegueIdentifier:#"successLogin" sender:nil];
Try this code
Note: Change controller name as per your controllers
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController *navController;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"loginUserDetails"]) {
// Already logged in
ProfileViewController *profileVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ProfileVC"];
navController = [[UINavigationController alloc]initWithRootViewController:profileVC];
}else{
// Not Login Yet
LoginViewController *loginVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"LoginVC"];
navController = [[UINavigationController alloc]initWithRootViewController:loginVC];
}
self.window.rootViewController = navController;
}
// Write this code when user login successfully
if (/*Login Successfully*/) {
// Then add loginUserDetails in userdefaults.
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"loginUserDetails"];// Instead of nil pass here your object
[[NSUserDefaults standardUserDefaults] synchronize];
}
I'm using AppDelegate method. Why?
When the user click the okay Button, it will force the phone to redirect to a UIControllerView, which is naked to the user eyes.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Daily Vibes"
message:notification.alertBody
delegate:self cancelButtonTitle:#"Wokay"
otherButtonTitles:nil];
[alert show];
}
// Request to reload table view data
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadData" object:self];
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Wokay"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"Vibes"];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
}
}
I'm getting error of the following:
Warning: Attempt to present <UIViewController: 0x109721840> on <UINavigationController: 0x10921abe0> whose view is not in the window hierarchy!
Is it possible to accomplish it?
Scenario:
User set time via "DatePicker" then when alarm pop via AppDelegate, when the user click Okay. Then the user will be redirected to a page where a harmony message is displayed via UILabel. But the user has only one button on that page "Back". He has to set another time just to view the message via redirecting.
Example pic:
its because window.rootViewController has type UINavigationController, not UIViewController.
you should initialise a NavigationController.
UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:yourUIViewController];
self.window.rootViewController = mainNavigationController;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"Vibes"];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
That's the answer...
In order to show my login screen when the app loads, and not after the user logs in, I have decided to add an auth object in NSUserDefaults when the user logs in successfully. When the app is launched that auth parameter is checked, and the view controller is set accordingly (if the user is auth it'll show a feed, if not it'll show a login screen) In the latter case, I have the app delegate reset the root view controller to the feed after the user has logged in. Is this bad practice or is there a better way of doing this?
In the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
IIViewDeckController* deckController = [self generateControllerStack];
self.rightController = deckController.rightController;
self.centerController = deckController.centerController;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([[defaults objectForKey:#"auth"] isEqualToNumber:[NSNumber numberWithInt:1]]){
self.window.rootViewController = deckController;
}else{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:nil];
UIViewController* vc = [sb instantiateViewControllerWithIdentifier:#"loginViewController"];
self.window.rootViewController = vc;
}
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
return YES;
}
- (void) setRoots
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
IIViewDeckController* deckController = [self generateControllerStack];
self.rightController = deckController.rightController;
self.centerController = deckController.centerController;
self.window.rootViewController = deckController;
[self.window makeKeyAndVisible];
}
In the login view controller:
- (IBAction)loginClick:(id)sender {
if([_emailField.text length]>0&&[_passField.text length]>0){
NSString *user = _emailField.text;
NSString *pass = _passField.text;
[[API sharedInstance] login:user andPass:pass onCompletion:^(NSDictionary *json){
NSLog(#"%#", json);
if(![json objectForKey:#"error"]){
[API sharedInstance].authorized = 1;
NSNumber *auth = [NSNumber numberWithInt:1];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:auth forKey:#"auth"];
[defaults synchronize];
captureYouAppDelegate *app = [[UIApplication sharedApplication] delegate];
[app setRoots];
}else{
[API sharedInstance].authorized = 0;
}
}];
}else{
if([_emailField.text length]<1){
[_emailField becomeFirstResponder];
}else{
[_passField becomeFirstResponder];
}
}
}
I'm wondering if there is a better or easier way than doing that. Thank you!
Just to clarify. I had reset UIWindow's rootViewController before without any problem but when attempting to do so while allowing device rotation I ran into some issues — Rotation just stopped working.
I found the following directly from Apple's docs while trying to debug. The link below has a number of guidelines about working with UIWindow. These are all related to device rotation but still good to know.
Short answer, use a root controller and add child view controllers. You can then swap out the child VCs with no problem.
• You have added your view controller's UIView property to UIWindow as a subview.
Developers are discouraged from adding the view property of any view controller as a subview of UIWindow. Your application's root view controller should be assigned to the app window's rootViewController property either in Interface Builder, or at runtime before returning from application:didFinishLaunchingWithOptions:. If you need to display content from more than one view controller simultaneously, you should define your own container view controller and use it as the root view controller. See Creating Custom Container View Controllers.
Check this technical Q&A for more details.
I don't think reset the window.rootViewController is a bad practice. However, there is no need to recreate a window.
If you don't want to use the previous view controller, just replace the window's rootViewController with the new view controller. If you do want to switch back to your previous view controller, use -presentViewController: animated: completion: to present your view controller may be a better alternative.
There is no need to alloc window again you can directly set this
window.rootViewController = yourVC;
Step By Step i am showing the Good Practice to use of rootviewcontroller with the help of UINavigationController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.splash = [[SplashViewController alloc] initWithNibName: #"SplashViewController" bundle: nil];
self.window.rootViewController = self.splash;
[self.window makeKeyAndVisible];
DLog(#"finished initializing .....");
[self setRootViewController];
return YES;
}
- (void) setRootViewController
{
DLog(#"setRootViewController");
if (self.sessionManager.isLoggedIn)
{
[self navigateToHomeController];
} else {
[self navigateToLoginController];
}
}
- (void) navigateToHomeController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"kStoryBoard" bundle: nil];
UINavigationController* homeNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"kHomeNavController"];
NSArray* controllers = [homeNavigationController viewControllers];
if([controllers lastObject])
{
if ([[controllers objectAtIndex:0] isKindOfClass:[HomeViewController class]]) {
HomeViewController* homeController = (HomeViewController*) [controllers objectAtIndex:0];
self.window.rootViewController = [[OLNavigationViewController alloc] initWithRootViewController: homeController];
}
}
}
- (void) navigateToLoginController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"kStoryBoard" bundle: nil];
UINavigationController* loginNavigationController = [storyboard instantiateViewControllerWithIdentifier:#"kLoginNavController"];
if ([loginNavigationController isKindOfClass:[OLLoginViewController class]]) {
OLLoginViewController* loginController = (OLLoginViewController*) loginNavigationController;
loginController.shouldHideToolBar = YES;
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController: loginController];
}
}