【问题标题】:Core Data fatal error: unexpectedly found nil while unwrapping an Optional valueCore Data 致命错误:在展开 Optional 值时意外发现 nil
【发布时间】:2016-08-19 06:48:40
【问题描述】:

当前出现致命错误:在执行这行代码deliveries = employee.delievery?.allObjects as! [NSManagedObject] 时,解包 Optional 值时意外发现 nil

我目前正在从另一个 tableView 像这样 var employees : [NSManagedObject]!prepareForSegue 这样发送一个员工

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue == "DelieverySegue"{
        let employeeDeliveries = segue.destinationViewController as! DelieveryTableViewController



        let indexPath = self.tableView.indexPathForSelectedRow



        let selectedEmployee = employees[indexPath!.row] as! Employee

        employeeDeliveries.employee = selectedEmployee





    }
}

我之所以prepareForSegue 喜欢这样是因为我正在继续使用的tableView 有一个变量var employee: Employee!

一旦我去 segue,它就会在我的 DeliveryTableViewController 中的 viewDidLoad() 中的这行代码处崩溃

deliveries = employee.delievery?.allObjects as! [NSManagedObject]

我的NSManagedObject 看起来像两者。

extension Employee {

@NSManaged var first: String?
@NSManaged var last: String?
@NSManaged var phoneNumber: String?
@NSManaged var wage: NSNumber?
@NSManaged var id: NSNumber?
@NSManaged var delievery: NSSet?

}

extension Delivery {

@NSManaged var address: String?
@NSManaged var phoneNumber: String?
@NSManaged var subTotal: NSNumber?
@NSManaged var total: NSNumber?
@NSManaged var employee: Employee?

}

这就是我在我的另一个 viewController 中设置关系的方式,这会创建一个新的交付

@IBAction func saveButton(sender: AnyObject) {

    let description = NSEntityDescription.entityForName("Employee", inManagedObjectContext: manageObjectContext)


    let employee = Employee(entity: (description)!, insertIntoManagedObjectContext: manageObjectContext)
    employee.first = first.text
    employee.last = last.text
    employee.phoneNumber = phoneNumber.text
    employee.wage = Float(wage.text!)
    employee.id = Int(employeeId.text!)


    do{
        try
        manageObjectContext.save()
        first.text = ""
        last.text = ""
        phoneNumber.text = ""
        wage.text = ""
        employeeId.text = ""
        status.text = "Success!"



    }catch let error as NSError{

        status.text = error.localizedFailureReason
    }

}

我是不是写错了?...我已经在 Employee 和 Delivery 之间建立了关系。我目前正在尝试在单击EmployeeTableViewController 中的特定员工时显示我要发送的员工的交货情况

我在运行时得到的,在转到DeliveryTableViewController 后失败了

【问题讨论】:

  • 不要强制转换或使用 [Delivery] 作为 obj。在继续之前使用 if let 或 guard 检查现有的值。
  • 为什么不声明为employee.delievery?.allObjects 为! [Delievert_entity] ???
  • 好吧,我的DeliveryTableViewController 中有一个名为var deliveries : [NSManagedObject]! 的变量,我可以执行`deliveries = employee.delievery?.allObjects as! [交付]` ? @SandeepBhandari
  • fizzy :是的,如果您声明 var 交付:[交付]!我相信:)
  • @SandeepBhandari 关注无效

标签: ios swift uitableview core-data fatal-error


【解决方案1】:

虽然您的代码无法确定问题的根源,但您的编码风格是问题的一部分:

deliveries = employee.delievery?.allObjects as! [NSManagedObject]

编写 Swift 代码是一种非常不安全的方式,并且在出现问题时不会给你任何答案。相反,考虑这样写:

guard let delievery = employee.delivevery else {
  print("Employee: \(employee)")
  fatalError("No deliver object referenced by employee")
}
guard let deliveries = delievery.allObjects as? [NSManagedObject] else {
  fatalError("Unexpected class type in allObjects")
}

通过此更改,您可以查看您是否没有delievery 对象,或者您对allObjects 的调用是否存在问题。

继续说下去,为什么要调用 allObjects? Employee 与称为delieveryDelivery 有关系。这意味着它返回一个NSSet。为什么要打电话给allObjects?这只是将它变成一个数组,这只是集合的另一种风格。

无论如何,在 Swift 中强制向下转换是 BAD 并且应该避免,除非你绝对确定你每次都会得到一个对象。在这种情况下,您没有这种保证,应该使用if letguard let 来确认您得到了什么。

嘿,马库斯,我要上传一张图片,说明当我选择一名员工并转到我的 DeliveryTableViewController 时会发生什么

好的,这表明即使是员工也可以是 nil 并且意外地是 nil。我猜你有一个这样的实例变量:

var employee: Employee!

同样,这在 Swift 中是一个坏习惯。你应该把它写成一个适当的可选:

var employee: Employee?

然后在需要时打开它:

guard let empl = employee else {
  fatalError("Employee not set")
}
guard let delievery = empl.delivevery else {
  print("Employee: \(employee)")
  fatalError("No deliver object referenced by employee")
}
deliveries = delievery

现在您将有一个正确解包的 Delivery 对象集合分配给您的实例变量,您可以从那里显示它们。

NSFetchedResultsController

说了这么多,您不应该像这样显示交货。你真的应该改用NSFetchedResultsController。像这样的:

guard let emp = employee else {
    fatalError("Employee not assigned")
}
let fetch = NSFetchRequest(entityName: "Delivery")
fetch.predicate = NSPredicate(format: "employee == %@", emp)

let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetch, context: emp.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

//Finish implementing the NSFetchedResultsController

然后使用NSFetchedResultsController 在您的UITableView 中显示交货。

有道理,所以如果您在上面查看我的 EmployeeTableViewController prepareForSegue,我会怎么做,这显然是不正确的。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    guard let identifier = segue.identifier else { 
        fatalError("Segue without an identifier")
    }
    switch identifier {
    case "DelieverySegue":
        guard let employeeDeliveries = segue.destinationViewController as? DelieveryTableViewController else {
            fatalError("Unexpected view controller class")
        }
        guard let indexPath = self.tableView.indexPathForSelectedRow else {
            fatalError("No row selected")
        }
        let employee = fetchedResultsController.objectAtIndexPath(indexPath)
        //Use a NSFetchedResultsController here also
        //let selectedEmployee = employees[indexPath!.row] as! Employee
        employeeDeliveries.employee = employee
    default: break
    }
}

同样,我也会在这里使用NSFetchedResultsController,而不是数组。这就是NSFetchedResultsController 的设计目的。

但是,如果您愿意,您仍然可以使用您的阵列。我不会推荐它。

这里的错误是您将segue 视为String 而不是。您必须从 UIStoryboardSegue 对象中提取 identifier,然后将其与您期望的标识符进行比较。

【讨论】:

  • 感谢您回复我...我实现了您建议的代码,但它因同样的错误而崩溃。 “致命错误:在展开可选值时意外发现 nil”你建议我做什么?
  • 那不是那行代码。您是否打开了异常断点?如果是这样,它在哪一行代码上中断?如果没有,请将其打开并重新启动应用程序:)
  • 嘿,马库斯,我要上传一张图片,说明当我选择一名员工并转到我的 DeliveryTableViewController 时会发生什么
  • 查看我的更新。假设您在运行时看到“Employee not set”,这表明您没有将 Empoyee 传递到此视图控制器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
相关资源
最近更新 更多