我正在逐个文件地将我的项目之一转换为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
objective-c 中的类似语句正常工作,返回nil,但我看到swift中的
objectForKey
声明为func objectForKey(defaultName: String!) -> AnyObject!
注意最后的感叹号,似乎必须从函数中返回一个对象,但是我认为正确的声明(使其像在objc中一样工作)应该以?结尾。
因此,我认为该行为已更改,并且未在文档中编写。
您是否认为这是一个错误(因此我将其归档)还是缺少某些东西?
谢谢
最佳答案
编辑
自从在最终的Swift版本中,Apple更改了NSUserDefaults上的objectForKey的方法声明(以及从 objective-c 桥接的许多其他方法),以返回可选(?),而不再隐含地解开了可选(!),此答案不再更新。
结束编辑
好的,我读得更好!在声明中,与!不同。使用变量时。
!声明中的内容表示该变量是隐式解包的(在Swift书中,请阅读“隐式解开的可选属性”和“无主引用和隐式解开的可选属性”两章,以更好地理解其含义)
简而言之,它意味着返回值仍可以为nil,但是由于它“很少”发生,因此返回值/变量未标记为可选(带有?)。
这样做是为了避免程序员每次使用更干净的代码时都要解开该值(使用if语句检查并解开该值)。
但是,第一个问题是EXC_BAD_INSTRUCTION是在错误的行上给出的,因为使用此语句
let defaultKey = AppUserDefaults.SelectedMonth.value()
let defaults = NSUserDefaults.standardUserDefaults()
let result : AnyObject = defaults.objectForKey(defaultKey)
return NSString(UTF8String: "")
未给出错误。(未返回结果,但objectForKey调用未失败)
因此,这又使我重新走对了路,并理解了隐式解开的Optionals的含义。
解决方案很简单,因为返回的值可以为nil,所以
selectedMonth
变量应带有?。 (标记为可选)或! (被标记为隐式解包的可选)例子
1)返回AnyObject?可选值作为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()
}
}
关于ios - Swift和NSUserDefaults-用户默认为空时为EXC_BAD_INSTRUCTION,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24032863/