NSUserDefault 常量不更新
NSUserDefault constant not updating
我在我的应用程序中实现了 NSUserDefaults
,正确的值在两次启动之间保持不变,但是当引用我创建的常量时,当默认值在会话期间更改时,这些值不会更新。
我确定我的问题源于使用常量引用 NSUserDefaults
,但我可以看到它为我节省了多少代码,如果 feasible/good 我想坚持使用这种方法实践。我不确定如何为新的 NSUserDefault
值更新常量。我没有崩溃——只是陈旧的值。
我的设置
AppDelegate.swift
我使用 NSUserDefaults
在我的应用程序中存储一些整数值。在 AppDelegate.swift
中,我检查它们是否已设置。这行得通。
PreferencesViewController.swift
我配置了一个 PreferencesVC
,它填充了默认值并允许用户更改默认值。我放了一些 print
语句来验证新的 NSUserDefaults
值,当它们被保存时。这行得通。
MyTableViewController.swift
我在 a 上声明了常量,所以我可以 trim 减少冗长的代码。
// Import Statements
@import UIKit
// Constants I declare here so they're accessible throughout the app.
let kDefaultActiveTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultActiveTime")
let kDefaultBreakTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultBreakTime")
let kDefaultRounds = NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
// Class declaration
class MyTableViewController: UITableViewController
在我的 cellForRowAtIndexPath
中,我使用默认常量计算时间并为单元格上的标签输出字符串。这是行:
// boilerplate cellForRowAtIndexPath omitted
let customCell = tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! RoutineSelectionTableViewCell
let routine = fetchedResultsController.objectAtIndexPath(indexPath) as! SavedRoutines
// ** This doesn't update w/ tableView.reloadData()
customCell.routineInformationLabel.text = String(format: "Time to complete - %@", formatTimeInSeconds(totalRoutineTime(routine.items! as NSOrderedSet)))
以下是用于为 routineInformationLabel.text
创建字符串的方法:
// Time computation methods
func totalRoutineTime(routine: NSOrderedSet) -> Int {
var totalRounds = 0
for item in routine {
// get the total of rounds
totalStretchRounds += (((item as! MyNSManagedObject).sideMultiplier?.integerValue)!) * kDefaultRounds
}
let totalActiveTime = totalRounds * kDefaultActiveTime
let totalBreakTime = (totalRounds - 1) * kDefaultBreakTime // subtract 1 rest period for last item
return totalActiveTime + totalBreakTime
}
func formatTimeInSeconds(totalSeconds: Int) -> String {
let seconds = totalSeconds % 60
let minutes = (totalSeconds / 60) % 60
let hours = totalSeconds / 3600
let stringHours = hours > 9 ? String(hours) : "0" + String(hours)
let stringMinutes = minutes > 9 ? String(minutes) : "0" + String(minutes)
let stringSeconds = seconds > 9 ? String(seconds) : "0" + String(seconds)
if hours > 0 {
return "\(stringHours):\(stringMinutes):\(stringSeconds)"
}
else {
return "\(stringMinutes):\(stringSeconds)"
}
}
我尝试创建一个观察者以在保存 NSUserDefaults
时重新加载 tableView,但这似乎并没有起到作用。我也试过在 viewDidAppear
、viewWillAppear
中加入 tableView.reloadData()
,等等。w/o 真幸运。
感谢您的阅读。我欢迎你的建议。
看起来所有的常量确实为您提供了更简洁、更易读的代码。我建议在 class 中编写私有辅助函数来做同样的事情。读入和读出 NSUserDefaults 非常快,应该不会出现问题。我也同意另一个答案的评论,没有必要同步。通常建议反对。让 iOS 系统为您处理。它完全有能力这样做。同步默认值会将它们写入磁盘,它会在准备就绪时执行此操作。否则,它将保留并从内存中读取数据。
我没有在您的代码中看到任何明显的错误,但我最好的猜测是在某些时候默认值正在更新并且常量已经设置。所以基本上,一旦 class 被加载,它们就再也不会被设置。
要以更简洁、易于输入的方式获取值,请考虑像这样的私有函数:
private func getDefaultRounds() -> Int {
return NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
}
只需 getDefaultRounds()
即可在 class 中的任何位置访问
我接受了 Kyle 的解决方案,但我尝试了一些作为学习练习,我将其抛出以了解人们的想法:
与其重复键入代码,不如记住我的密钥是什么,无论是 Int
、Float
还是 Bool
等,我创建了一个 Struct
访问值:
struct Defaults {
let activeTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultActiveTime")
let breakTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultBreakTime")
let rounds = NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
}
当我需要访问 NSUserDefaults
值时,它们会动态更新。似乎及时将它们声明为常量 "snapshots",但它们不会更新。
当我需要默认值但不想输入它们时,我输入:
Defaults().rounds
Defaults().activeTime
Defaults().breakTime
我还没有遇到任何 "gotchas" 这种方法......还没有。如果有人对此有改进的建议,我会洗耳恭听。
我在我的应用程序中实现了 NSUserDefaults
,正确的值在两次启动之间保持不变,但是当引用我创建的常量时,当默认值在会话期间更改时,这些值不会更新。
我确定我的问题源于使用常量引用 NSUserDefaults
,但我可以看到它为我节省了多少代码,如果 feasible/good 我想坚持使用这种方法实践。我不确定如何为新的 NSUserDefault
值更新常量。我没有崩溃——只是陈旧的值。
我的设置
AppDelegate.swift
我使用 NSUserDefaults
在我的应用程序中存储一些整数值。在 AppDelegate.swift
中,我检查它们是否已设置。这行得通。
PreferencesViewController.swift
我配置了一个 PreferencesVC
,它填充了默认值并允许用户更改默认值。我放了一些 print
语句来验证新的 NSUserDefaults
值,当它们被保存时。这行得通。
MyTableViewController.swift
我在 a 上声明了常量,所以我可以 trim 减少冗长的代码。
// Import Statements
@import UIKit
// Constants I declare here so they're accessible throughout the app.
let kDefaultActiveTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultActiveTime")
let kDefaultBreakTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultBreakTime")
let kDefaultRounds = NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
// Class declaration
class MyTableViewController: UITableViewController
在我的 cellForRowAtIndexPath
中,我使用默认常量计算时间并为单元格上的标签输出字符串。这是行:
// boilerplate cellForRowAtIndexPath omitted
let customCell = tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! RoutineSelectionTableViewCell
let routine = fetchedResultsController.objectAtIndexPath(indexPath) as! SavedRoutines
// ** This doesn't update w/ tableView.reloadData()
customCell.routineInformationLabel.text = String(format: "Time to complete - %@", formatTimeInSeconds(totalRoutineTime(routine.items! as NSOrderedSet)))
以下是用于为 routineInformationLabel.text
创建字符串的方法:
// Time computation methods
func totalRoutineTime(routine: NSOrderedSet) -> Int {
var totalRounds = 0
for item in routine {
// get the total of rounds
totalStretchRounds += (((item as! MyNSManagedObject).sideMultiplier?.integerValue)!) * kDefaultRounds
}
let totalActiveTime = totalRounds * kDefaultActiveTime
let totalBreakTime = (totalRounds - 1) * kDefaultBreakTime // subtract 1 rest period for last item
return totalActiveTime + totalBreakTime
}
func formatTimeInSeconds(totalSeconds: Int) -> String {
let seconds = totalSeconds % 60
let minutes = (totalSeconds / 60) % 60
let hours = totalSeconds / 3600
let stringHours = hours > 9 ? String(hours) : "0" + String(hours)
let stringMinutes = minutes > 9 ? String(minutes) : "0" + String(minutes)
let stringSeconds = seconds > 9 ? String(seconds) : "0" + String(seconds)
if hours > 0 {
return "\(stringHours):\(stringMinutes):\(stringSeconds)"
}
else {
return "\(stringMinutes):\(stringSeconds)"
}
}
我尝试创建一个观察者以在保存 NSUserDefaults
时重新加载 tableView,但这似乎并没有起到作用。我也试过在 viewDidAppear
、viewWillAppear
中加入 tableView.reloadData()
,等等。w/o 真幸运。
感谢您的阅读。我欢迎你的建议。
看起来所有的常量确实为您提供了更简洁、更易读的代码。我建议在 class 中编写私有辅助函数来做同样的事情。读入和读出 NSUserDefaults 非常快,应该不会出现问题。我也同意另一个答案的评论,没有必要同步。通常建议反对。让 iOS 系统为您处理。它完全有能力这样做。同步默认值会将它们写入磁盘,它会在准备就绪时执行此操作。否则,它将保留并从内存中读取数据。
我没有在您的代码中看到任何明显的错误,但我最好的猜测是在某些时候默认值正在更新并且常量已经设置。所以基本上,一旦 class 被加载,它们就再也不会被设置。
要以更简洁、易于输入的方式获取值,请考虑像这样的私有函数:
private func getDefaultRounds() -> Int {
return NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
}
只需 getDefaultRounds()
我接受了 Kyle 的解决方案,但我尝试了一些作为学习练习,我将其抛出以了解人们的想法:
与其重复键入代码,不如记住我的密钥是什么,无论是 Int
、Float
还是 Bool
等,我创建了一个 Struct
访问值:
struct Defaults {
let activeTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultActiveTime")
let breakTime = NSUserDefaults.standardUserDefaults().integerForKey("defaultBreakTime")
let rounds = NSUserDefaults.standardUserDefaults().integerForKey("defaultRounds")
}
当我需要访问 NSUserDefaults
值时,它们会动态更新。似乎及时将它们声明为常量 "snapshots",但它们不会更新。
当我需要默认值但不想输入它们时,我输入:
Defaults().rounds
Defaults().activeTime
Defaults().breakTime
我还没有遇到任何 "gotchas" 这种方法......还没有。如果有人对此有改进的建议,我会洗耳恭听。