Swift和NSUserDefaults – 当用户默认为空时EXC_BAD_INSTRUCTION
我正在将我的一个项目转换为Swift,逐个文件。 我有NSUserDefaults一个奇怪的行为。 我使用一个NSString而不是一个string与其他代码兼容
var selectedMonth : NSString { get { return NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) as NSString } set { NSUserDefaults.standardUserDefaults().setObject(self, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
该方法正确地获取/设置属性,但是当第一次执行应用程序和用户默认EXC_BAD_INSTRUCTION
空,我收到一个EXC_BAD_INSTRUCTION
错误return NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) as NSString
问题不在于回报,因为我可以“扩大”这个陈述:
let defaultKey = AppUserDefaults.SelectedMonth.value() let defaults = NSUserDefaults.standardUserDefaults() // defaults is correctly set let result : AnyObject = defaults.objectForKey(defaultKey) // <-- the error is here return result as NSString
在目标C中的类似的语句工作正常,返回零,但我看到在swift中objectForKey
的声明是
func objectForKey(defaultName: String!) -> AnyObject!
注意最后感叹号,似乎一个对象必须从函数返回,但我认为正确的声明(使其像objc一样工作)应该以? 所以我认为这个行为改变了,而不是写在文档中。
你认为这是一个错误(所以我会提交)还是我错过了什么? 谢谢
编辑
这个答案不再更新,因为在最后的Swift版本中,Apple更改了NSUserDefaults(和其他许多从目标c桥接的方法)的objectForKey方法声明,以返回一个可选的(?),并且不再包含一个Implicitly Unwrapped Optional(!)
结束编辑
好吧,我读了更好的文档和意义! 在一个声明,这是不同的! 当使用一个variables。
! 在一个声明中意味着这个variables被隐式地解开(在Swift书上,阅读“Implicitly Unwrapped Optionals”和“Unowned References and Implicitly Unwrapped Optional Properties”章节,以更好地理解它的含义
简而言之,这意味着返回值仍然可以为零,但由于它发生“很less”,所以返回值/variables没有被标记为可选的(用?)。 这是为了避免程序员需要每次打开值(检查if语句和解包值)具有更清晰的代码。
但是,第一个问题是EXC_BAD_INSTRUCTION在错误的行上,因为使用了这个语句
let defaultKey = AppUserDefaults.SelectedMonth.value() let defaults = NSUserDefaults.standardUserDefaults() let result : AnyObject = defaults.objectForKey(defaultKey) return NSString(UTF8String: "")
没有给出错误(结果没有被返回,但objectForKey调用没有失败)所以这又给我带来了正确的方式,并理解隐式展开的可选项
解决scheme很简单,因为返回的值可以为零variablesselectedMonth
应该有一个? (被标记为可选)或者! (被标记为隐式解包可选)
例子
1)返回AnyObject? optinal值作为var selectedMonth的types
var selectedMonth : AnyObject? { get { return NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) } set { NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
2)返回一个可选的NSString?,将返回types转换为AnyObject? 然后到NSString?
var selectedMonth : NSString? { get { return NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) as AnyObject? as NSString? } set { NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
这就像写作
var selectedMonth : NSString? { get { var returnValue : AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) return returnValue as NSString? } set { NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
3)返回一个隐式包装的NSString!
var selectedMonth : NSString! { get { var returnValue : AnyObject! = NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) return returnValue as NSString! } set { NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
4)短版
var selectedMonth : NSString! { get { return NSUserDefaults.standardUserDefaults().objectForKey(AppUserDefaults.SelectedMonth.value()) as AnyObject! as NSString! } set { NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: AppUserDefaults.SelectedMonth.value()) NSUserDefaults.standardUserDefaults().synchronize() } }
尝试这个
if let myObject : AnyObject = defaults.objectForKey(defaultKey){ // grab myObject here return myObject; }else{ // .. // return nil; }