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() } }
该方法在获取/设置属性时正常工作,但是当应用程序第一次执行并且用户默认值为空时,在返回NSUserDefaults.standardUserDefaults()时收到EXC_BAD_INSTRUCTION错误.objectForKey(AppUserDefaults.SelectedMonth.value())作为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中工作)应该以a结尾?
所以我认为行为发生了变化,并没有写在文档中.
你认为这是一个错误(所以我会提交)或者我错过了什么?
谢谢
解决方法
这个答案不再更新,因为在最后的Swift版本中,Apple更改了NSUserDefaults上的objectForKey的方法声明(以及从目标c桥接的许多其他方法)返回一个可选的(?),而不再有一个隐式解包可选(!)
结束编辑
好的,我阅读更好的文档和意思!在一个宣言中,这是不一样的!当使用变量时.
!在一个声明中意味着该变量被隐式解开(在Swift书中,读取“隐含展开的可选项”和“未知引用和隐式解开的可选属性”章节,以更好地了解它的含义
简单来说,这意味着返回值仍然可以为零,但是由于它很少发生,所以返回值/变量没有被标记为可选的(带有?).
这是为了避免程序员需要每次打开值(使用if语句检查并打开值)来清除代码.
然而,第一个问题是EXC_BAD_INSTRUCTION被错误地列出,因为这个声明
let defaultKey = AppUserDefaults.SelectedMonth.value() let defaults = NSUserDefaults.standardUserDefaults() let result : AnyObject = defaults.objectForKey(defaultKey) return NSString(UTF8String: "")
没有给出错误(结果没有返回,但是objectForKey调用没有失败)
所以这再次给了我正确的方法,并且理解了隐含解开的可选项的含义
解决方案很简单,因为返回的值可以为零,selectMonth应该有一个变量? (被标记为可选)或一个! (被标记为隐式展开的可选)
例子
1)返回AnyObject? optinal值作为var selectedMonth的类型
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?将返回类型转换为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() } }