我正在将我的一个项目转换为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
上收到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中的类似语句正常工作,返回nil,但我看到swift中objectForKey
的声明是
func objectForKey(defaultName: String!) -> AnyObject!
注意结尾处的感叹号,似乎必须从函数返回一个对象,但我认为正确的声明(使其在objc中工作)应该以?结尾? 所以我认为行为发生了变化,并没有写在文档中。
你认为这是一个错误(所以我会提交它)或者我错过了什么? 感谢
答案 0 :(得分:12)
修改强>
这个答案不再更新,因为在最终的Swift版本中Apple更改了NSUserDefaults上的objectForKey的方法声明(以及从目标c桥接的许多其他方法)以返回一个可选的(?)而不再是一个隐式解包的可选(!)
结束编辑
好的,我更好地阅读了文档和含义!在一个声明,这是一个不同于!使用变量时。
!在一个声明中意味着该变量是隐式展开的(在Swift书上,读取&#34;隐式展开的Optionals&#34;和#34;无主参考和隐式展开的可选属性&#34;章节以更好地理解它的含义< / p>
简单来说,这意味着返回值仍然可以为零,但由于它很少发生&#34;很少&#34;,返回值/变量未标记为可选(带?)。 这样做是为了避免程序员每次需要打开值(使用if语句检查并解开值)并使用更干净的代码。
然而,第一个问题是EXC_BAD_INSTRUCTION是在错误的行上给出的,因为这句话
let defaultKey = AppUserDefaults.SelectedMonth.value()
let defaults = NSUserDefaults.standardUserDefaults()
let result : AnyObject = defaults.objectForKey(defaultKey)
return NSString(UTF8String: "")
没有给出错误。(结果没有返回但是objectForKey调用没有失败) 因此,这让我再次走上正确的路,并理解隐含解开的选项的含义
解决方案很简单,因为返回的值可以是nil变量selectedMonth
应该有? (标记为可选)或a! (标记为隐式展开的可选)
实施例
1)返回AnyObject? optinal value作为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()
}
}
答案 1 :(得分:4)
试试这个
if let myObject : AnyObject = defaults.objectForKey(defaultKey){
// grab myObject here
return myObject;
}else{
// .. //
return nil;
}