This question already exists:
Load up different view on first run
Closed 9 years ago.
I'm programming an app at the moment which requires on the first run for the app toload a different view in which the user can select its prefered settings.Here's the code
implementation AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// Determining Storyboard identifier for first view
// Determining Storyboard identifier for first view
NSString *storyboardID = [self hasEverBeenLaunched]? #"MainView" : #"LoginView";
// Setting proper view as a rootViewController
self.window.rootViewController = [self.window.rootViewController.storyboardinstantiateViewControllerWithIdentifier: #"view45"] ;
It then goes on with the following code:
- (BOOL)hasEverBeenLaunched
{
// A boolean which determines if app has eer been launched
BOOL hasBeenLaunched;
// Testig if application has launched before and if it has to show the home-login screen to login
// to social networks (facebook, Twitter)
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"HasAlreadyLaunched"]) {
// Setting variable to YES because app has been launched before
hasBeenLaunched = YES;
NSLog(#"App has been already launched");
} else {
// Setting variable to NO because app hasn't been launched before
hasBeenLaunched = NO;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"HasAlreadyLaunched"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"This is the first run ever...");
}
return hasBeenLaunched;
}
Just a few quick notes: View 45 is the initial starting up view which should only show once, Otherwise the main view controller is ticked under atrributes to be the initial view controller(The one that always loads up at the start, after the first run)
So the problem is that it only ever loads view 45 ,the first run view, but whats causing that exactly ?
The problem is in the following line:
self.window.rootViewController = [self.window.rootViewController.storyboardinstantiateViewControllerWithIdentifier: #"view45"] ;
It is ignoring the value of storyboardID and just using the string #"view45", so that's why you'll always get the same one every single time.
If you want to fix it, change it to the following line:
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardID];
You can see that now it is making use of the value in storyboardID.
Related
This question already has answers here:
Show screen on first launch only in iOS
(8 answers)
Closed 5 years ago.
I'm trying to create an tutorial screen that displays only during the first opening of an app. i know i should use user defaults but how and where ? in method viewDidLoad or on app delegate class ?
Try this one
- (BOOL)isAppAlreadyLaunchedOnce {
BOOL isRememberMe = [[NSUserDefaults standardUserDefaults]boolForKey:#"isAppAlreadyLaunchedOnce"];
if (isRememberMe) {
return YES;
}
else{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isAppAlreadyLaunchedOnce"];
return NO;
}
}
Store the status whether the Tutorial View is displayed or not in NSUserDefaults.
If you want to decide at startup to show or not show the Tutorial View you should do it in App Delegate didFinishLaunchingWithOptions
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"shouldShowTutorial"])
//show tutorial
}
else{
//don't show tutorial
}
On the first time when the Tutorial View has been displayed set a flag in NSUserDefaults.
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"shouldShowTutorial"];
#Maddy has given correct answer but let me just clarify one thing why we will not use viewDidLoad?
Why we are using didFinishLaunch
in short:
viewDidLoad
System has already decided which View to load when application launches .By default it's the "Main" storyboard's initial view controller
didFinishLaunch
System has done all tasks to show your app but has not decided which view to load. Thats why you can control here to show your tutorial screen first. :)
I created my iMessage extension, when I try to open it, the first screen appears but it is totally frozen, and it does not react in any way.
I've put logs in the viewDidLoad of that first view and nothing appears there, after a few seconds I can already see those logs.
To make the application freezing lose that status, user has to slide screen left or right and back again.
I've tried looking all over the web for someone who happens to be the same, but I could not find anything.
It does not come to mind more screenshots or portions of code add, if you think I should provide some additional information, just let me know
Any help would be appreciated.
Thank you.
UPDATE:
This is my Project Structure.
This is my viewDidLoad code.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"here viewDidLoad iMessage ext~~~!");
[self applyCornerRadiusToBtn];
[self registerPresentationAction];
NSDictionary *user = [self getUserInfoFromHostApp];
if (user) {
NSLog(#"Here != null user info");
//It is assumed that when you enter this point and run this log, the app should navigate to the next screen, but it does not.
[self performSegueWithIdentifier:#"goToYoutubeListIm" sender:nil];
} else {
NSLog(#"Here userInfo null");
}
}
- (NSDictionary *)getUserInfoFromHostApp
{
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.xxxxx"];
NSDictionary *userNameSaved = [myDefaults objectForKey:#"userInfoExt"];;
NSLog(#"userNameSaved in xxxx Ext ==> %#",userNameSaved);
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.xxxx"];
NSLog(#"groupURL ==> %#",groupURL);
return userNameSaved;
}
For all concerned I have found the problem or problems to be accurate.
1) I was creating my controllers type MSMessagesAppViewController. Apparently there should only be one controller of this type.
2) I had logic in the viewDidAppear in my MSMessagesAppViewController. For some strange reason this also caused the problem, I had to get the logic out there and force the user to interact with a button to execute the logic that was in the didAppear
I want to make a guided tour of my app on the first launch, but not a separated guided tour where I show images of the app. I'd like to have multiple chat-bubbles just like this one:
And when I click somewhere on the screen, the next one pops up. I haven't found a single tutorial for this on the web, so maybe I'm just not using the right keywords...
Anyways, thanks a lot !
You can use an Int e.g. int firstLaunch and save it with NSUserDefaults to detect first launch. Then add a view to the UIView in the story board and make it fill the Application screen and give it a grey color and and transparency.
Then add the images of the bubble in the position you want them in the view.
Below would go in the ViewDidLoad:
firstLaunch = [[NSUserDefaults standardUserDefaults] integerForKey:#"FirstLaunch"];
if (firstLaunch == 0) {
firstLaunch = 1;
[[NSUserDefaults standardUserDefaults] setInteger:firstLaunch forKey:#"FirstLaunch"];
ViewName.hidden = NO;
bubble1Image.hidden = NO;
}
I'm using WSCoachMarksView to give my users a walkthrough the first time they open up the app, and I obviously only want this to run that first time, and never again after that. I followed the instructions in the documentation that tells you to put the respective code that I have in viewDidAppearso that it only runs once, but it doesn't seem to work.
It still runs through the walkthrough every time the app is open. Is there anything I'm not doing properly to detect the app running previously and setting the BOOL so that it doesn't run again?
SearchViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Setup coach marks
NSArray *coachMarks = #[
#{
#"rect": [NSValue valueWithCGRect:(CGRect){{50,168},{220,45}}],
#"caption": #"Just browsing? We'll only notify you periodically of new matches. Need it soon? We'll notify you more frequently, and match you with items that are closer to you."
},
];
self.coachMarksView = [[WSCoachMarksView alloc] initWithFrame:self.tabBarController.view.bounds coachMarks:coachMarks];
[self.tabBarController.view addSubview:self.coachMarksView];
self.coachMarksView.animationDuration = 0.5f;
self.coachMarksView.enableContinueLabel = YES;
[self.coachMarksView start];
}
- (void)viewDidAppear:(BOOL)animated {
// Show coach marks
BOOL coachMarksShown = [[NSUserDefaults standardUserDefaults] boolForKey:#"WSCoachMarksShown"];
if (coachMarksShown == NO) {
// Don't show again
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"WSCoachMarksShown"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Show coach marks
[self.coachMarksView start];
}
}
in viewDidLoad you always start your intro, regardless of what you've set in NSUserDefaults. The check in viewDidAppear is correct, but it's already playing at that time
I have setup a custom url scheme for my app, this is how it works when app is not running in background:
custom url link arrives in email, upon clicking brings the login view from storyboard
Upon clicking the login button will take to the you requested tab in tab controller
So far so good.
Here is the problem I am having:
If I click on the custom url link again from email When the app has already been loaded once and its running in the background it does not bring the login view again
My question is what do I need to do load the login view again when I click the custom url link more than once.
Custom url scheme works perfectly the first time but not when the app has already been running. I tried to debug this ... when I click custom url scheme link "handleOpenURL:(NSURL *)url" method is called in my AppDelegate.m file so what do I need to do to load the login screen again from storyboard and how do I check if the login screen is already loaded in memory ... Login screen is my start view in storyboard, below is how handleOpenUrl function looks like in my app delegate.
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
if(!url){
return NO;
}
// check if email link was clicked
if ([[url scheme] isEqualToString:#"docova"]) {
NSString *urlString = [url absoluteString];
NSLog(#"URL Parameter string: %#", [url query]);
NSLog(#"incoming url => %#", urlString);
// NSArray *arrayQStrings=[self getDataOfQueryString:urlString];
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
NSLog(#"query dict: %#", [dict valueForKey:#"action"]);
NSLog(#"query dict: %#", [dict valueForKey:#"docpath"]);
//[self.tabBarController setSelectedIndex:1]; // tab 3
//[self.parentViewController.tabBarController setSelectedIndex:1]; // tab 3
/* save user data ***/
NSUserDefaults *appPrefs = [NSUserDefaults standardUserDefaults];
[appPrefs setObject:[dict valueForKey:#"action"] forKey:#"action"]; // reset these after using it
[appPrefs setObject:[dict valueForKey:#"docpath"] forKey:#"docpath"]; // reset these after using it
// save data to application preference
[appPrefs synchronize];
return YES;
}
return NO;
}
Can someone suggest on how to bring a view from storyboard upfront when the app has already been running. I know there is activity stack in android, is there something like that in ios as well ...
I was able to solve this by using the commnets from mialkan and also have to change the handleOpenUrl method ( this is deprecated) to " application:openURL:sourceApplication:annotation", so in my openUrl method, I check for specific action and invoked the view accordingly, see below:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
loginView = [storyboard instantiateViewControllerWithIdentifier:#"SIDLoginViewController"];
self.window.rootViewController = loginView;
Thanks mialkan :)
As I understand, your interface builder structure like this
Navigation Controller -> Login View Controller -> Tabbar Controller
When your app already run in background, if the user open the app via mail link you want show login view first?
you can use NSNotificationCenter to invoke a method to pop to Login view.
Here is a ex. code to register your notification and to call it.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(popToLoginView:) name:#"popToLoginViewNotification" object:nil];
To notifiy methods.
[[NSNotificationCenter defaultCenter] postNotificationName:#"popToLoginViewNotification" object:nil];
if you have TabbarController classes put popToLoginView method. Or each view controller of tabbar put popToLoginView method. in view check if its current view, with this code
if (viewController.isViewLoaded && viewController.view.window) {
// viewController is visible
}
then pop to login view.
I hope this helps.