2013-02-15 57 views
3

我有超时功能,如果应用程序闲置(在后台)一段时间,我超时我的应用程序并将用户发送到登录屏幕。我在应用程序委托中将用户默认设置为“timedOut”的键设置为YES,然后在每个视图控制器中引用该键,如果为YES,则继续登录屏幕。在登录屏幕上,如果“timedOut”为YES,则会显示“会话超时”标签。我的问题是,如果我登录,然后很快注销,即使在显示标签后将该键明确设置为NO,然后同步用户默认值,也会显示标签。 如果我等待一两秒钟并注销,标签就会隐藏起来。我已经解决了“问题”,但想了解行为。NSUserDefaults没有快速更新值

来自视图的代码确实在我的登录视图控制器中加载。你可能会认为这会将isTimedOut更改为NO,但是当我执行快速注销时,viewdidload会再次被调用,但isTimedOut为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

我取代以上我的应用程序委托,而不是和NSUserDefaults的的“怪异”的行为走了使用属性的代码。

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; 

} 

更多的代码

要注销,我有UIButtonBarItem调用SEGUE编程。 doLogout属性告诉登录视图控制器运行注销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设置在应用程序委托中的一个位置。

-(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; 
} 

} 
+1

不知道要了解清楚你的问题。但一个小问题:为什么不使用某种内存而不是userDefaults?这里有什么好处?如果我是你,我会在NSDate中存储“去背景”,然后在应用程序转到前景时进行比较。 – Vinzius 2013-02-15 23:17:29

+0

提供完整的代码。至于目前尚不清楚发生了什么。每次调用同步时,NSUserDefaults都会将所有内容存储在内存中并保存为闪存,因此即使快速重新登录,也不应引起此类问题。 – 2013-02-17 02:47:02

回答

2

使用此:

要保存布尔:

[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isTimedOut"]; 

加载一个布尔值:

if ([[NSUserDefaults standardUserDefaults] boolForKey:@"isTimedOut"] == YES) { 
     //it equals yes 
     } 

    else { 
     //it equals no 
     } 
2

你为什么不尝试这样的事情?我没有看到你的完整项目,但它应该像一个魅力。

- (void)viewDidLoad { 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; 
} 

然后...

- (void)applicationWillResignActive:(UIApplication *)application 
{ 
    [[NSUserDefaults standardUserDefaults] setValue:[NSDate date] forKey:@"sleepTime"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
} 

和...

- (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 
     } 
    } 
} 
+0

当应用程序首次启动时,不会调用UIApplicationWillEnterForegroundNotification。我正在使用UIApplicationDidBecomeActiveNotification,它在应用程序放入后台或首次启动时调用。 – Nate 2013-02-18 15:39:15

+0

@Nate,当然,这只是一个想法,你可以随意定制它。 – holex 2013-02-18 15:55:37