NSArray、NSUserDefaults、可选项和解包混乱

NSArray, NSUserDefaults, optionals and unwrapping mess

我在处理看似简单的事情时遇到了严重的错误。

我有一个 NSArray,我会在应用程序第一次启动时用文字填充它。

然后在某个时候我想使用数组,所以我在 class:

中声明了另一个数组

var localArray = NSUserDefaults.standardUserDefaults().arrayForKey("array")!

然后我想在标签中显示一个词。当用户按下按钮 (forward/backward) 时,会出现 next/previous 字样。很简单,对吧?是的,但不知何故我得到了非常讨厌的错误。

对于 next/previous 个单词,我有 2 种方法:

    @IBAction func nextWord(sender: AnyObject) {
        if let currentIndex = localArray.indexOf(label.text!)
        {
            if currentIndex == localArray.count-1
            {
                label.text = localArray[0] as? String
            }
            else
            {
                label.text = localArray[currentIndex+1]
            }
        }
    }

另一种倒退的方法是相同的(有必要的修改)。

而在 viewDidLoad 中,我只是设置了标签的文本:

label.text = localArray[0] as? String

问题出在 if let 语句上。在使用用户默认值之前,我只是用一些字符串初始化了 localArray。一切正常。但是一旦我添加了用户默认值,疯狂就开始了。我在使用 localArray 的任何地方都有错误,说数组没有展开。所以我在初始化本地的时候在user defaults数组后面加了!

但是最后 2 个错误(在 if let 语句中)毫无意义。现在 indexOf() 方法抛出一个错误,这是以前没有发生过的事情。它还告诉我它无法将字符串 (label.text!) 转换为 @noescape (AnyObject) throws -> Bool.

所以现在我需要将该字符串转换为 NSString 才能正常工作或怎样?我在用户默认值中发现了一些关于 "bridging" 与数组相关的内容。那是我的问题吗?

这就是困扰我的问题:为什么我必须明确地将数组中的字符串向下转换为字符串?为什么 indexOf 方法改变了。

未包装的可选是否像非可选一样?

如果用取模运算符实现会好很多。

let newIndex = (oldIndex + 1) % localArray.count

我需要更多信息来回答您的大部分问题。 localArray 的类型是什么?

您正在创建的对象不是数组(至少编译器不知道它是)。函数 arrayForKey("array")! 返回 AnyObject,而不是 Array。所以从那时起,编译器认为这个对象是一个 AnyObject。我将如何解决这个问题(可能不是正确的方法)是立即投射数组:

if let myArray: AnyObject! = NSUserDefaults.standardUserDefaults().objectForKey("array") {
    //Your array exists, cast it now and use it
    var localArray =  myArray as! Array<String>
}
else
{
    //Something bad happened, the array isn't there.
}

那你稍后就得解包了。如果您知道此对象将始终存在并且转换将始终有效,您可以将 ? 更改为 !

查看 this answer 了解更多信息。

你应该总是(并且对于大部分强制向下转换)。为了从 NSUserDefaults 中安全地检索您的数组(使用正确的类型),您可以执行以下操作:

if let array = NSUserDefaults.standardUserDefaults().arrayForKey("array") as? [String] {
    // do something with your [String] array
} else {
    // do error handling
}

这样做的目的是从 NSUserDefaults 中获取一个 [AnyObject]?,代表您的数组。然后,您可以使用 as? 有条件地向下转换并将其桥接回 Swift 字符串数组 ([String])。如果这不成功,您可以安全地处理这种情况。