【问题标题】:unexpectedly found nil while unwrapping an Optional value?解包 Optional 值时意外发现 nil?
【发布时间】:2016-06-04 08:00:37
【问题描述】:

我遇到了一个错误:“在展开可选值时意外发现 nil” 当我在 coreData 中插入新数据并重新加载我的 tableview 时,我想起了这个函数

  var unique = [String]()
  var loadMovie = [String:[Movie]]()


 func insertMovie(movie : Movie) {
    let genre = movie.genre!
    if unique.contains(genre) {
        loadMovie[genre]!.append(movie)
    } else {
        unique.append(genre)
        loadMovie[genre] = [movie]
    }
}

并获取数据:

 func fetchAndSetResults() {
    let app = UIApplication.sharedApplication().delegate as! AppDelegate
    let context = app.managedObjectContext
    let fetchRequest  = NSFetchRequest(entityName: "Movie")

    do {
        let movies = try context.executeFetchRequest(fetchRequest) as! [Movie]
        loadMovie.removeAll()
        for movie in movies {
        insertMovie(movie)
        }
    } catch let err as NSError {
        print(err.debugDescription)
    }
}

应用程序因上述在线错误而崩溃:“loadMovie[genre]!.append(movie)”,但如果我重新加载应用程序,我的数据将存储并在 tableview 中可见。有什么问题?

【问题讨论】:

  • 您是否在 Stack Overflow 上搜索过现有答案?
  • 阅读可选绑定和一般可选:Swift中的一个关键概念,我怀疑你还没有完全掌握,看到您的强制解包... = movie.genre!... loadMovie[genre]!。请注意,当编译器要求您解包选项时,您不应盲目相信编译器:在其当前状态下,它通常只会询问您是否要执行强制解包 (!),这通常是一个不好的建议编译器。我个人怀疑,关于 SO 的所有 “意外发现 nil ...” 问题中的很大一部分都是基于对编译器建议的健全性的信任。
  • 在我提出的解决方案中,genre 是非可选的。您更改了它,这会导致错误。为了使用 genre 作为部分标识符,您需要一个非可选值。
  • @user1679705 再说一遍:不要相信这里的编译器建议,而是阅读例如optional binding。我敦促您在继续您的 Swift 之旅之前掌握可选项的概念以及如何安全地解开它们(这很可能会为您节省很多时间,并让您避免许多常见的 Swift 初学者陷阱)。跨度>
  • @vadian 不管怎样,我不认为我们可以说可选项在 Swift 中不是一个重要的概念,即使它可能是最佳实践 i> 尽可能使用非可选类型(对此我不会说是或否;我经常使用可选类型,但也许这是我自己缺乏的......)。后者不应排除指出前者,否则我们迟早会从 OP 那里得到另一个关于强制解包选项的问题。您对课程细节的反馈/...Movie 可能对 OP 解决这个问题很有价值;但可选选项在这里非常重要。

标签: ios swift uitableview core-data


【解决方案1】:

你解包的可选变量意味着你只解决编译时错误。迅速展开变量意味着它表示该变量不会得到 nil。你只是告诉编译器。但是现在你得到 nil(运行时错误),你需要使用可选绑定来处理这个问题。

  if let movies = try context.executeFetchRequest(fetchRequest)
{
            loadMovie.removeAll()
}

【讨论】:

  • 我想要做的是避免 nil 错误而不是管理它。当我关闭视图“添加电影”并在我的表上调用函数“fetchAndSetResults”时,loadMovie.removeAll() 上出现了 nil 值的错误。事实上,如果我取消这条线,我没有错误,但所有电影都会被复制!我需要避免这种情况。
  • 先听这个你就明白了youtube.com/watch?v=W1s9ZjDkSN0
【解决方案2】:

您的变量 loadMovie 是一个字典,其中字符串作为键,电影 数组作为每个键存储的内容。如果您收到错误 "unexpectedly found nil while unwrapping an Optional value" for line " loadMovie[genre]!.append(movie)" 这意味着毫无疑问名为 genre 的字符串有时不会作为键存储在 loadMovie 字典中。

使用下面的代码首先确保您可以获得为该键存储的数组(存储在 genre 字符串中),如果不能,则打印出字符串以便调试, 找出缺少的密钥。

var unique = [String]()
var loadMovie = [String:[Movie]]()

func insertMovie(movie : Movie) {
    let genre = movie.genre!
    if unique.contains(genre) {
        if let genreArray = loadMovie[genre]{
            genreArray.append(movie)
        } else {
            NSLog("The missing genre: \(genre)")
        }
    } else {
        unique.append(genre)
        loadMovie[genre] = [movie]
    }
}

任何时候你想要一个可以为 nil(不存在)的值,你可以使用上面的 if/let 模式。因此,对于 cmets 中的第二个问题,您可以将 return loadMovie[genre].count 替换为:

 if let genreArray = loadMovie[genre]{
     return genreArray.count
 } else {
     return 0  // zero because there are no items 
 }

还有其他方法。您应该查看一个很好的基本 swift 教程,例如:http://www.tutorialspoint.com/swift/

如果您查看有关选项的部分,这应该会更加清楚。在堆栈溢出时,通常希望您首先尝试自己找出答案,并理解基本理论。不幸的是,这就是为什么你得到这么多反对票的原因。我希望这有帮助。

如果这对您有所帮助,请点击旁边的复选标记接受此答案。

【讨论】:

  • 您好,该功能现在可以运行,但是当应用程序创建该部分时出现错误: override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { letgenre = unique[section]
  • 因为在您尝试使用 genre 时,genre 字符串被用作 loadMovie 字典的键在字典中找不到该键,将返回 nil。在 Swift 中,当你“强制解包”一个 nil 值时(当你使用感叹号时:!)你的应用程序将会崩溃。您正在使用没有值的键。您需要先检查,如果为零则返回零。
  • 是的,但我不希望这种类型是可选的,因为正如@vadian 所说,这是无稽之谈。 Core Data 自己对此表示敬意,我无法将流派更改为非可选。我怎样才能做到这一点?我找不到要解决的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多