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