一个核心数据属性导致离开应用程序并再次打开时EXC_BAD_ACCESS(代码=1)



我现在完全被卡住了:

设置

我有一个UISplitViewController。启动应用程序时,一切加载良好,我可以保存、删除、编辑数据,没有问题。然而,当我按下主页按钮(applicationDidEnterBackground(并返回应用程序时,我会得到一个EXC_BAD_ACCESS (code=1, address=0x60)
这似乎只发生在我的一个特点上。

func configureCell(cell: NoteTableViewCell, atIndexPath indexPath: NSIndexPath) {
    let note = fetchController.fetchedResultsController.objectAtIndexPath(indexPath) as! Note
    //deal with NSDate's crap
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    //set date and title Label
    cell.dateLabel.text = dateFormatter.stringFromDate(note.date)
    cell.titleLabel.text = note.title
}  

错误发生在note.date上,当移除它并放置NSDate()时,没有错误。请注意,代码中还有note.title不会崩溃
我对CoreData的背景了解不多,所以我不知道从哪里开始。

潜在重要代码

这是Note NSManagedObject类

class Note: NSManagedObject {
@NSManaged var date: NSDate
@NSManaged var details: String
@NSManaged var title: String
@NSManaged var tag: String
@NSManaged var noteToFolder: NoteData
@NSManaged var noteToData: NSSet
convenience init(date: NSDate, title: String, details: String,tag: String, insertIntoManagedContext context: NSManagedObjectContext){
    let entity: AnyObject = NSEntityDescription.entityForName("Note", inManagedObjectContext: context)!
    self.init(entity: entity as! NSEntityDescription, insertIntoManagedObjectContext: context)
    self.date = date
    self.title = title
    self.details = details
    self.tag = tag

}  

func saveNote(title: String, detail: String,
    predicate: NSPredicate, fetchRequest: NSFetchRequest,
    context: NSManagedObjectContext) {
        fetchRequest.predicate = predicate

        do {
            let fetchResults = try context.executeFetchRequest(fetchRequest) as? [Note]
            fetchResults!.first?.title = title
            fetchResults!.first?.details = detail
            fetchResults!.first?.date = NSDate()
            try context.save()

        } catch {
            print("Couldn't fetch results")
        }

这是VC的细节,VC所做的只是加载注释的标题和细节。但即使我不打开这个VC,我也可以重现错误。

func saveNote() {
    //configure the request
    let predicate = NSPredicate(format: "self == %@", note.objectID)
    let fetchRequest = NSFetchRequest(entityName: "Note")
    fetchRequest.predicate = predicate
    note.saveNote(titleTextField.text!, detail: detailTextView.text,
        predicate: predicate, fetchRequest: fetchRequest, context: context!)
}

这是在主VC中(只显示带有注释标题和日期的UITableView(,当创建新注释时,这在UIAlertViewController:内调用

let saveAction = UIAlertAction(title: "Save",
        style: UIAlertActionStyle.Default,
        handler: { (action: UIAlertAction!) -> Void in
            //get textfield
            let textField = alert.textFields![0]
            //Set note title
            var noteName: String?
            if textField == "" {
                noteName = "New Note"
            }else {
                noteName = textField.text
            }
            //save the note
            _ = Note(date: NSDate(), title: noteName!, details: "",tag: "defaut", insertIntoManagedContext: self.context)
            do {
                try self.context.save()
            } catch {
                print("Couldn't save context")
            }
    })

其他信息

这篇文章最初是用Swift 1.2在Xcode 6.4上写的,从未出现过问题。当我升级时,我遇到了很多现在已经修复的问题,所以这在Xcode 7上从未起过作用。
据我所知,我没有在离开应用程序时调用的任何函数中编写任何内容
我试着启用Exception Breakpoints,但没有成功。我也没有尝试过实现多线程CoreData。

编辑
当加载Detail VC,然后离开应用程序并重新打开它时,应用程序加载时不会出现错误。当移回Master VC时,没有错误,但UITableViewController是空的。

编辑2
正如@mundi所暗示的,储蓄可能存在问题。我使用的是fetchedResultsController,当检查提取的数据时,我会在控制台中得到这个:

离开应用程序前:

Printing description of note:
<Super_Notes.Note: 0x7fe320c22710> (entity: Note; id: 0xd000000000080000 <x-coredata://48C2DE25-C58B-446F-995F-F97084BCFCCE/Note/p2> ; data: {
    date = "2015-10-15 14:50:32 +0000";
    details = "This is Zetta ";
    noteToData = "<relationship fault: 0x7fe320dbbcb0 'noteToData'>";
    noteToFoler = nil;
    tag = defaut;
    title = Zetta;
})

重新打开应用时

Printing description of note:
<Super_Notes.Note: 0x7fe320c22710> (entity: <null>; id: 0xd000000000080000 <x-coredata://48C2DE25-C58B-446F-995F-F97084BCFCCE/Note/p2> ; data: <fault>)

这是我用来拉纸条的代码:

func configureCell(cell: NoteTableViewCell, atIndexPath indexPath: NSIndexPath) {
        let note = fetchController.fetchedResultsController.objectAtIndexPath(indexPath) as! Note
        //deal with NSDate's crap
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateStyle = .MediumStyle
        //set date and title Label
        cell.dateLabel.text = dateFormatter.stringFromDate(note.date)
        cell.titleLabel.text = note.title
    }

这就是我配置NSFetchedResultsController的方式,它在viewDidLoad:中被调用

func configFetchController() {
        //configure fetch controller
        fetchController.context = context
        let defaultSortDescriptor = NSSortDescriptor(key: "date", ascending: false)
        fetchController.sortDescriptors = [defaultSortDescriptor]
        fetchController.entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: context)!
        fetchController.fetchedResultsController.delegate = self
        do {
            try fetchController.fetchedResultsController.performFetch()
        } catch {
            print("An error occured while performing Fetch")
        }
    }

如果你还需要什么,请告诉我!:-(

谢谢!

离开应用程序时,似乎没有正确保存日期。日期格式化程序将因nil日期而崩溃。

我认为saveNote函数什么也不做,因为谓词不检索任何内容。注意谓词

NSPredicate(format: "self == %@", note.objectID) 

永远都是假的。这意味着结果的first将为零,并且没有对象被实际修改或保存。如果你想要一个特定对象的谓词,它应该是

NSPredicate(format: "self = %@", note)

您的saveNote函数似乎有些做作。只发送要更新的参数并在修改的地方处理保存,会不会简单得多?

func updateNote(newTitle: String, newDetail: String) {
    self.title = newTitle
    self.detail = newDetail
    self.date = NSDate()
}

我怀疑您可能试图在不同的线程上修改对象。这件事更复杂,有很多注意事项,但有一件事与您的原始设计接近,那就是传递上下文和NSManagedObjectID

func updateNote(newTitle: String, newDetail: String, context: 
                NSManagedObjectContext, objectId: NSManagedObjectID) {
  let note = context.objectWithID(objectId) as! Note
  note.title = newTitle
  note.detail = newDetail
  note.date = NSDate()
  do { try context.save() } catch {}
}

如果你将其用于子上下文,你仍然需要确保在离开应用程序之前保存所有上下文,否则更改不会写入持久存储。

最新更新