【问题标题】:NSUserDefaults not updating value quicklyNSUserDefaults 没有快速更新值
【发布时间】:2013-02-15 18:06:47
【问题描述】:

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

视图中的代码确实加载到了我的登录视图控制器中。您会认为这会将 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];

}

更新

我使用我的应用程序委托中的属性而不是 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;
}

}

【问题讨论】:

  • 不确定是否清楚地了解您的问题。但是一个小问题:为什么不使用某种内存来代替 userDefaults?这里有什么好处?如果我是你,我会将“进入后台”存储在 NSDate 中,然后在应用程序进入前台时进行比较。
  • 提供完整代码。目前还不清楚发生了什么。 NSUserDefaults 将所有内容存储在内存中,并在每次调用同步时保存到闪存中,因此即使快速重新登录也不会导致此类问题。

标签: ios xcode nsuserdefaults


【解决方案1】:

使用这个:

保存布尔值:

[[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
            }
        }
    }
    

    【讨论】:

    • UIApplicationWillEnterForegroundNotification 在应用程序首次启动时不会被调用。我正在使用 UIApplicationDidBecomeActiveNotification,它在应用程序进入后台或首次启动时调用。
    • @Nate,当然,这只是一个想法,您可以随意定制。
    猜你喜欢
    • 2017-12-18
    • 2016-04-26
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多