I want to show an alertview on third time my app is launched. I have searched everywhere but can't find the solution. How can I know that my app has been launched for the third time?
Thanks in Advance
you can use these methods to read and write to file with very little effort
+ (void) setSetting: (NSString *)key value: (NSString *)value {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:value forKey:[NSString stringWithFormat:#"%#", key]];
[defaults synchronize];
}
+ (NSString *) getSetting: (NSString *)key defaultVal: (NSString *)defaultVal {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *setting = [defaults stringForKey:[NSString stringWithFormat:#"%#", key]];
if (setting == nil) {
setting = defaultVal;
}
return setting;
}
you can just update a value you have stored in the user defaults each time the didFinishLaunchingWithOptions: in your appDelegate is triggered
Thats easy. Save an NSNumber in your NSUserDefaults and increase it every time you're launching your application. When it hits 3 then show an alert.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)options {
// ...
if ([self plusPlusLaunchCount] == 3) {
[self showRateUsAlert];
}
return YES;
}
- (void)showRateUsAlert {
// show the Rate Us alert view
}
- (NSInteger)plusPlusLaunchCount {
static NSString *Key = #"launchCount";
NSInteger count = 1 + [[NSUserDefaults standardUserDefaults] integerForKey:Key];
[[NSUserDefaults standardUserDefaults] setInteger:count forKey:Key];
return count;
}
Related
I have an app which should only show the settings page once: when the app is opened for the first time.
Now this works, and when the user presses the middle button on the iPhone it then reopens the app and carries on from the main screen - that's great. But if I double click on the iPhone button and swipe the application off, it will then go to the settings screen again and not to where it was.
Why is it doing that? How can I make my app only show its settings once?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSUserDefaults *settingsscreen = [NSUserDefaults standardUserDefaults];
[settingsscreen registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],#"firstTime", nil]];
BOOL firstTime = [settingsscreen boolForKey:#"firstTime"];
if ( firstTime==YES) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SettingsShown"];
[[NSUserDefaults standardUserDefaults] synchronize];
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"SetUpNav"];
}
else
{
return YES;
}
}
Don't use if ( firstTime==YES) { based on #"firstTime", because that flag is never actually saved. You should be using the flag saved with the #"SettingsShown" key.
BOOL firstTime = [settingsscreen boolForKey:#"SettingsShown"];
if (!firstTime) {
...
Instead doing in appDelegate try to acheive it in setting Page itself
-(void) viewDidLoad {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
username = [defaults objectForKey:#"username"];
if (username != NULL ) {
[self selfLogin];
}
}
-(void)selfLogin{
nextPageController = [[NextPageViewController alloc]init];
[self.navigationController pushViewController:nextPageController animated:YES];
}
I am saving Textfield text using NSUserDefaults on button click in ViewController2
My code is
ButtonClick()
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
[userDefaults synchronize];
}
Then ViewDidLoad method i am Retrieving like this
-(void)viewDidLoad
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[keyWordArray addObject:[userDefaults objectForKey:#"Keywords"]];
[userDefaults synchronize];
}
Here i am assigning this keyWordArray to tableview
like cell.textlabel.text =[keyWordArray objectAtIndex:indexPath.row];
First i entered text(First) in textfield and click button it is showing in table like
First
Second time i entered text (second) in textfield and click button it is showing table like
First
Second
Here everything working fine. The problem is when i come to viewController2 from ViewController1. It is showing last entered value only
like
Second
what going wrong here?
Try This
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
[selt.tableView reload]; //reload the table every time a new text is added
}
-(void)viewDidLoad {
if([[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"]==nil){
keyWordArray = [[NSMutableArray alloc] init];
}
else{
keyWordArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
}
}
Try this,
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
}
and
-(void)viewDidLoad
{
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
if (!array) {
keyWordArray = [[NSMutableArray alloc] init];
} else {
keyWordArray = [NSMutableArray arrayWithArray:nameArray];
}
}
Since you are overriding your
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
every then and there your every object in the array will be referring to your [userDefaults setObject:keyWordField.text forKey:#"Keywords"]; object thats y the problem comes
Because if you are navigate to another viewController. since the your user default value save in second only.
After pop to back through viewDidLoad is loaded. so far its have second string only save in User Default.
that way it display second only.
You code is overwrite the last value and remove previous values from NSUserDefault. You have to use array to stored all value and you have save array into NSUserDefault.
NSMutableArray *aryDataDefault = [[NSUserDefaults standardUserDefaults] valueForKey:#"YourKey"];
[aryDataDefault addObject:textfield.text];
[[NSUserDefaults standardUserDefaults] setObject:aryDataDefault forKey:#"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
Although the code for NSUserDefaults seems quite simple I cannot make it work.
I have a settingViews where user can disable the sound or not. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.soundSettings.font = [UIFont rw_snapFontWithSize:24.0f];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"stateForSoundSwitch"]) {
NSLog(#"Sound is ON");
self.soundStatus.on=YES;
} else {
self.soundStatus.on=NO;
NSLog(#"Sound is OFF");
}
}
- (IBAction)soundSwitchChanged:(id)sender
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (self.soundStatus.on) {
NSLog(#"Sound is enabled");
[defaults setBool:true forKey:#"stateForSoundSwitch"];
}
else {
NSLog(#"Sound is disabled");
[defaults setBool:false forKey:#"stateForSoundSwitch"];
}
[defaults synchronize];
}
But even if I change the switch to FALSE, every time I log in the settings screen the value is TRUE. What am I missing?
setBool:forKey: expects a BOOL. Try using YES or NO instead of true or false (which is type bool, lowercase).
Also you should access it with boolForKey instead of objectForKey.
Your logic test will always be YES if you've ever set the object in NSUserDefaults since you're effectively testing if the key exists (i.e. not nil), not whether it is actually set to YES/NO.
In other words, change:
if ([defaults objectForKey:#"stateForSoundSwitch"]) {
to this:
if ([defaults boolForKey:#"stateForSoundSwitch"] == YES) {
I have at timeout feature where if the app is idle (in background) for a period of time, I timeout my app and send the user to the login screen. I set the "timedOut" key in user defaults to YES in my application delegate, then reference that key in each view controller, where if it is YES, I segue to the login screen. On the login screen I have a label that displays "Session has timed out" if the "timedOut" is YES. My issue is that if I login, then logout very quickly, the label is displayed, even though I explicitly set that key to NO right after I show the label and then synchronize the user defaults. If I wait a second or two and logout, the label is hidden like it should be. I have solved the "problem", but would like to understand the behavior.
Code from view did load in my login view controller. You would think this changes the isTimedOut to NO, but when I do a quick logout viewdidload is called again, but isTimedOut is YES.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
sessionLabel.hidden = YES;
isTimedOut = [defaults boolForKey:#"isTimedOut"];
if (isTimedOut == YES)
{
sessionLabel.hidden = NO;
defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:NO forKey:#"isTimedOut"];
isTimedOut = NO;
NSLog(#"Timed Out has been reset to %s",[defaults boolForKey:#"isTimedOut"] ? "YES" : "NO");
[defaults synchronize];
}
UPDATE
I replaced the code above using a property in my app delegate instead of NSUserDefaults and the "strange" behavior went away.
eONavAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
isTimedOut = appDelegate.isTimedOut;
sessionLabel.hidden = YES;
//isTimedOut = [defaults boolForKey:#"isTimedOut"];
NSLog(#"Timed Out has been reset to %s",appDelegate.isTimedOut ? "YES" : "NO");
if (isTimedOut == YES)
{
appDelegate.isTimedOut = NO;
sessionLabel.hidden = NO;
}
MORE CODE
To logout, I have UIButtonBarItem calling a segue programmatically. The doLogout property tells the login view controller to run a logout API.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"logoutSegue"])
{
// Get reference to the destination view controller
eoLoginViewController *vc = [segue destinationViewController];
vc.doLogout = YES;
}
}
isTimedOut is set in one location in the app delegate.
-(void)timeoutWithDate:(NSDate *)currentDate
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDate *previousDate = [defaults objectForKey:#"enteredBackground"];
NSTimeInterval distanceBetweenDates = [currentDate timeIntervalSinceDate:previousDate];//TimeInterval is in seconds
NSLog(#"Time between dates in seconds %f",distanceBetweenDates);
double minutesInAnHour = 60;
double minutesBetweenDates = distanceBetweenDates / minutesInAnHour;
NSLog(#"minutesBetweenDates %f",minutesBetweenDates);
if(minutesBetweenDates > 60)
{
isTimedOut = YES;
}
else
{
isTimedOut = NO;
}
}
Use this:
To save a Bool:
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"isTimedOut"];
To Load a Bool:
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"isTimedOut"] == YES) {
//it equals yes
}
else {
//it equals no
}
why don't you try something like this? I didn't see your full project but it should work like a charm.
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
then...
- (void)applicationWillResignActive:(UIApplication *)application
{
[[NSUserDefaults standardUserDefaults] setValue:[NSDate date] forKey:#"sleepTime"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and...
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSInteger _timeoutInSeconds = 300;
NSDate *_sleepTime = [[NSUserDefaults standardUserDefaults] valueForKey:#"sleepTime"];
if (_sleepTime) {
NSCalendar *_calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *_dateComponents = [_calendar components:NSSecondCalendarUnit fromDate:_sleepTime toDate:[NSDate date] options:0];
if (_dateComponents.second > _timeoutInSeconds) {
// expired session
} else {
// valid session
}
}
}
I have used this method for logout facebook in app
- (void)fbDidLogout {
// Remove saved authorization information if it exists
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]) {
[defaults removeObjectForKey:#"FBAccessTokenKey"];
[defaults removeObjectForKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
NSLog(#"logout success!");
}
This method has been invoked, but when I relaunch app the facebook still know about my latest authorization.
My full implementation
I create singleton object for facebook instance.
this is my manager .h
#import <Foundation/Foundation.h>
#import "FBConnect.h"
#interface FacebookManager : NSObject <FBSessionDelegate> {
Facebook *facebook;
}
#property (nonatomic, strong) Facebook *facebook;
+ (FacebookManager *)sharedInstance;
- (void)initWithAppID:(NSString *)appID;
#end
this is singleton facebookmanager .m
#import "FacebookManager.h"
#implementation FacebookManager
#synthesize facebook;
static FacebookManager *_sharedInstance = nil;
+ (FacebookManager *)sharedInstance {
#synchronized(self) {
if (!_sharedInstance) {
_sharedInstance = [[FacebookManager alloc] init];
}
}
return _sharedInstance;
}
- (void)initWithAppID:(NSString *)appID {
facebook = [[Facebook alloc] initWithAppId:appID andDelegate:self];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]
&& [defaults objectForKey:#"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:#"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:#"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:nil];
}
}
- (void)fbDidLogout {
// Remove saved authorization information if it exists
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"FBAccessTokenKey"]) {
[defaults removeObjectForKey:#"FBAccessTokenKey"];
[defaults removeObjectForKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
NSLog(#"logout success!");
}
#end
in appDelegate I make next:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
fbManager = [FacebookManager sharedInstance];
[fbManager initWithAppID:#"myappid"];
... (some other code)
}
also add this code to app delegate:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [fbManager.facebook handleOpenURL:url];
}
- (void)fbDidLogin {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[fbManager.facebook accessToken] forKey:#"FBAccessTokenKey"];
[defaults setObject:[fbManager.facebook expirationDate] forKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
In other view controller I call this method for logout:
- (IBAction)logoutFacebook:(id)sender {
FacebookManager *fbManager = [FacebookManager sharedInstance];
[fbManager.facebook logout];
}
also in plist I have add needed url scheme.
Modify the Facebook.m code to this, which works for me.
-(void)logout:(id)delegate {
self.sessionDelegate = delegate;
[_accessToken release];
_accessToken = nil;
[_expirationDate release];
_expirationDate = nil;
NSHTTPCookieStorage *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *facebookCookies = [cookies cookiesForURL:[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies){
[cookies deleteCookie:cookie];
}
//Adds this one.
for (NSHTTPCookie *_cookie in cookies.cookies){
NSRange domainRange = [[_cookie domain] rangeOfString:#"facebook"];
if(domainRange.length > 0){
[cookies deleteCookie:_cookie];
}
}
if ([self.sessionDelegate respondsToSelector:#selector(fbDidLogout)]){
[_sessionDelegate fbDidLogout];
}
}
What do you mean by "when I relaunch app the facebook still know about my latest authorization" ? Does this mean your FB accesstoken is still valid? You still see the userdefaults values? What exactly?
If you mean that when you trigger the FB login again, it automatically logs you in again, then yes if you have the Facebook APP installed in iOS, the user will have to logout from the FB app manually to switch an account.
If the FB app is not installed, then yes the SSO should prompt the user to login again after initiating a logout.
That seems to be the way the ios sdk api with sso/oauth 2.0 works. I have not been able to logout completely even after clearing the tokens and I have not been able to switch users from the App. Got to go to the FB app to switch users
As a workaround, change the line in Facebook.m and disable the safariAuth
// [self authorizeWithFBAppAuth:YES safariAuth:YES];
[self authorizeWithFBAppAuth:NO safariAuth:NO]
But then you have to type in the username and password everytime you authorize.
In Facebook.m, add the following code to remove cookies at m.facebook.com domain.
- (void)invalidateSession {
...
NSArray* facebookMCookies = [cookies cookiesForURL:
[NSURL URLWithString:#"https://m.facebook.com"]];
for (NSHTTPCookie* cookie in facebookMCookies) {
[cookies deleteCookie:cookie];
}
...
}
I have tried with success this code:
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSLog(#"cache dir %#", cachesDirectory);
NSError *error = nil;
for (NSString *file in [fm contentsOfDirectoryAtPath:cachesDirectory error:&error]) {
BOOL success = [fm removeItemAtPath:[NSString stringWithFormat:#"%#/%#", cachesDirectory, file] error:&error];
if (!success || error) {
NSLog(#"Error delete file: %#, %#", file, error);
} else {
NSLog(#"Deleted file: %#", file);
}
}