如何防止致命错误:在展开可选值时意外发现 nil

Posted

技术标签:

【中文标题】如何防止致命错误:在展开可选值时意外发现 nil【英文标题】:How to prevent fatal error: unexpectedly found nil wile unwrapping an Optional value 【发布时间】:2016-05-22 14:18:31 【问题描述】:

所以我是核心数据的新手,开始学习一些教程并获得了一个非常基本的设置,其中从 AppDelegate 保存了 10 个分数并且工作正常(能够从控制台获取和打印)。

然后当我想在另一个 VC 中使用 fetchrequest 来检索已成功保存的数据时,我收到以下错误: 致命错误:在展开可选值时意外发现 nil。 这是检索数据的代码:

import Foundation
import CoreData
import UIKit


class testVC: UIViewController 
var managedObjectContext: NSManagedObjectContext!
var scores = [Scores]()

@IBOutlet weak var retrieveDataLabel: UIButton!
@IBOutlet weak var saveLabel: UIButton!
  override func viewDidLoad() 
    super.viewDidLoad()

     


@IBAction func retrieveData(sender: AnyObject) 
    let fetchRequest = NSFetchRequest(entityName: "Scores")
    do 
        if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [Scores]
            scores = results
            for result in results 
                if let gameScore = result.valueForKey("gameScore") as? Int
                    print("Your score is \(gameScore)")
                
            
        
    catch
        print("Error fetching data")
    

override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.

既然我在使用 if let .. 我不应该得到“错误获取数据”吗?而不是得到致命错误?为什么我在加载应用程序时可以检索数据,但在尝试使用相同代码在不同 VC 中检索数据时却不能?

我查看了其他与在展开可选值时发现的致命错误相关的问题: What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?

fatal error: unexpectedly found nil while unwrapping an Optional value 看来我基本上是在尝试检索不存在的东西,但数据确实保存了,我可以在启动应用程序时在控制台中检索它。使用相同的获取请求时,我希望在加载应用程序并检索数据时获得相同的结果,但事实并非如此。

我在这里缺少什么?感觉它应该是非常基本的,但由于某种原因在尝试了 2 天后无法让它工作。

用于保存和检索数据的应用委托代码:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
    // Override point for customization after application launch.
    //addTestData()
    let fetchRequest = NSFetchRequest(entityName: "Scores")
    do 
        if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
            for result in results 
                if let gameScore = result.valueForKey("gameScore") as? Int
                    print("Your score is  \(gameScore)")
                
            
        
    catch
        print("Error fetching data")
    

    return true

func addTestData()

    guard let entity = NSEntityDescription.entityForName("Scores", inManagedObjectContext: managedObjectContext) else
        fatalError("Could not find entity description")
    
    for i in 1...10
        let score = Scores(entity: entity, insertIntoManagedObjectContext: managedObjectContext)
        score.gameScore = i
    
    do 
        try managedObjectContext.save()
     catch 
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        let nserror = error as NSError
        NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
        abort()
    


任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

当您使用 if let 时,您正在检查是否可以将结果设为 Int。您想先查看该结果是否存在。试试这个:

for result in results 
            if let gameScore = result.valueForKey("gameScore") 
                print("Your score is \(gameScore as! Int)")
            
        

【讨论】:

以下返回错误:如果让结果...所以它在到达提取结果之前崩溃,但出现此错误:致命错误:在展开可选值时意外发现 nil 而不是如下: print("获取数据时出错") 尝试做和抓。你不需要它。如果您删除它可能会有所帮助【参考方案2】:

问题是nil NSManagedObjectContext(已声明但没有价值)

根据定义 executeFetchRequest 在成功时返回一个非可选数组,因为您应该从核心数据模型中知道实体 Scores 始终返回 Scores 对象,您可以安全地编写

do 
    scores = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Scores]

显然使用NSManagedObject 子类直接使用属性来避免类型转换。仅当属性 gameScore 被声明为可选时,才需要可选绑定。

    for result in results 
        if let gameScore = result.gameScore 
            print("Your score is \(gameScore)")
        

但是对于像分数这样的Int 值,非可选值比您可以将代码减少到更合理

    for result in results 
       print("Your score is \(result.gameScore)")
    

【讨论】:

【参考方案3】:

所以我确实设法让它工作,对 managedObjectContext 使用以下内容: 让 managedContext = AppDelegate().managedObjectContext

我仍然很困惑,为什么我没有收到 catch 中指定的错误,但至少它现在可以工作了。

感谢您的回答!

【讨论】:

以上是关于如何防止致命错误:在展开可选值时意外发现 nil的主要内容,如果未能解决你的问题,请参考以下文章

如何调试“致命错误:在展开可选值时意外发现 nil”

快速致命错误:在展开可选值时意外发现 nil

致命错误:在快速 Json 解析中展开可选值时意外发现 nil

致命错误:在展开可选值时意外发现 nil。迅速

致命错误:在展开可选值时意外发现 nil - 为啥?

如何修复“线程 1:致命错误:在展开可选值时意外发现 nil”错误? [复制]