【问题标题】:Unusual Core Data Behavior - Save one object effects another?不寻常的核心数据行为 - 保存一个对象会影响另一个对象?
【发布时间】:2015-10-17 00:24:29
【问题描述】:

所以我正在努力学习 Swift,我确信我做错了什么,但我不知道那可能是什么。

我正在编写一个笔记应用程序来帮助自己快速掌握这门语言。它具有一个表格视图(由 NSArrayController 填充)。单击表格视图中的注释会弹出一个视图控制器,其中显示注释的标题和正文。单击添加按钮会创建一个新的笔记管理对象并将其传递给与用于编辑的视图控制器相同的视图控制器。

在编辑笔记时,选择一些文本并按 command-l 的用户可以创建一个标题与所选文本相同的新笔记。

除了命令-l,一切都很好。这种行为是最不寻常的,我敢肯定,这是我造成的。

是这样的:

  1. 创建注释并填写标题和正文。假设它被称为“第一”,而正文是“这是第一个,而不是第二个”。
  2. 选择一些文本(“第二个”)并按 command-l。这会保存当前笔记,创建一个新的托管对象,填写标题(“第二个”),并将其显示在视图控制器中。输入正文(“这是第二个”)
  3. 保存笔记。
  4. 视图控制器现在列出了两个注释,这是它应该的。单击第一个音符(“第一个”)现在会显示第二个音符的描述。 ('这是第二个')

这里有一些代码:

从主(表视图)控制器:

override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
    if segue.identifier=="CreateNote" {
        let nextViewController = segue.destinationController as! DetailViewController
        nextViewController.managedContext=self.managedContext
        nextViewController.note = NSEntityDescription.insertNewObjectForEntityForName("Note", inManagedObjectContext: managedContext!) as! Note
    }
    else if segue.identifier=="EditNote" {
        let theSelection = tableView.selectedRow
        let theNote = noteArrayController?.arrangedObjects[theSelection] as! Note
        let nextViewController = segue.destinationController as! DetailViewController
        nextViewController.managedContext=self.managedContext
        nextViewController.note = theNote
    }
}

从细节视图控制器:

import AppKit

class DetailViewController: NSViewController, KeyNotificationProtocol {

    @IBOutlet weak var noteTitle: NSTextField!
    @IBOutlet var noteBody: TWTextView!

    @IBAction func backButton(sender: AnyObject) {
        saveNote()
        if historyStack.isNotEmpty() {
            note=findNoteByName(historyStack.pop())
            loadNote()
        }
    }

    @IBAction func dismissButton(sender: AnyObject) {
        saveNote()
        self.dismissController(self)
    }
    var managedContext: NSManagedObjectContext?
    var note: Note?
    var noteNameToLoad: String?
    var historyStack = Stack<String>()

    override func viewDidLoad() {
        super.viewDidLoad()
        loadNote()
        noteBody.keyDelegate = self

        var requestArray: [KeyRequest] = []

        requestArray.append(KeyRequest(theFlags: [NSEventModifierFlags.CommandKeyMask],
            theKey: "l",
            theTag: "link",
            theFunc: self.createLink))

        noteBody.keysOfInterest=requestArray
    }

    override func viewWillDisappear() {
        saveNote()
    }

    func keypressWasReceived(keypress: KeyNotificationData) {
        keypress.keypressRequest.funcToCall()
    }

    func createLink() {
        print("create link!")
        if(noteBody.selectedRange().length>0) {
            saveNote()
            if let swRange = noteBody.string?.rangeFromNSRange(noteBody.selectedRange()) {
                let selectedText = noteBody.string!.substringWithRange(swRange)
                let tempNote=findNoteByName(selectedText)
                if(tempNote==nil) {
                    historyStack.push((note?.title)!)
                    self.note = (NSEntityDescription.insertNewObjectForEntityForName("Note", inManagedObjectContext: managedContext!) as! Note)
                    self.note!.title=selectedText
                    self.note!.attributedBody=NSAttributedString(string: "New note")
                    loadNote()
                }
                else {
                    print("note exists")
                }
            }

        }
    }

    func saveNote() -> BooleanType {
        if (managedContext?.hasChanges != nil) {
            self.note?.title=noteTitle.stringValue
            self.note?.attributedBody=noteBody.textStorage
            var saved = false

            do {
                try managedContext?.save()
                saved = true
            }
            catch let error as NSError {
                print("Error saving \(error)", terminator: "")
            }

            return saved
        }
        else {
            return true
        }

    }

    func loadNote() {
        if self.note?.title==nil {
            self.note?.title=""
        }
        noteTitle.stringValue = (self.note?.title)!

        if(self.note?.attributedBody?.length>0) {
            noteBody.textStorage?.setAttributedString((self.note?.attributedBody)!)
        }
        else if(self.note?.body?.characters.count>0) {
            noteBody.textStorage?.setAttributedString(NSAttributedString(string: (self.note?.body)!))
        }
        else {
            noteBody.textStorage?.setAttributedString(NSAttributedString(string: ""))
        }

    }

    func findNoteByName(noteName: String) -> Note? {
        let freq = NSFetchRequest(entityName: "Note")
        freq.predicate = NSPredicate(format: "title == %@", noteName)
        var result: [Note]=[]
        do {
            result = try managedContext?.executeFetchRequest(freq) as! [Note]
        }
        catch let theError as NSError {
            print(theError)
            result=[]
        }

        if result.count>0 {
            return result[0]
        }
        else {
            return nil
        }
    }    
}

创建第一个注释:

按下command-l后,第一个音符被保存,第二个音符被创建:

保存第二条笔记后(点击完成),返回表格视图,点击第一条:

因此,为了了解发生了什么,我为 managedObjectContext 通知添加了 KVO。我在设置了所有核心数据的 appdelegate 中执行了此操作:

func applicationDidFinishLaunching(aNotification: NSNotification) {
    // Insert code here to initialize your application

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "shitHappened:", name: NSManagedObjectContextObjectsDidChangeNotification, object: managedObjectContext)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "shitHappened:", name: NSManagedObjectContextDidSaveNotification, object: managedObjectContext)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "shitHappened:", name: NSManagedObjectContextWillSaveNotification, object: managedObjectContext)
}

func shitHappened(sender: AnyObject) {
    print("-- something happened with core data --")
    print(sender)
}

监视我的观察者生成的输出,我没有看到第一个注释正在更新和保存,因此正文设置为第二个!这是其中的数据。在此日志数据的最后,有一条通知说 First Note 已被修改。在哪里?!

-- something happened with core data --
NSConcreteNotification 0x608000045c10 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    inserted = "{(\n    <testwiki.Note: 0x6100000a8fa0> (entity: Note; id: 0x610000020b40 <x-coredata:///Note/tBCC61422-BDB8-44EB-A1A0-D32126C892354> ; data: {\n    attributedBody = nil;\n    body = nil;\n    title = \"\";\n})\n)}";
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
}}
create link!
-- something happened with core data --
NSConcreteNotification 0x61000005af40 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
    updated = "{(\n    <testwiki.Note: 0x6100000a8fa0> (entity: Note; id: 0x610000020b40 <x-coredata:///Note/tBCC61422-BDB8-44EB-A1A0-D32126C892354> ; data: {\n    attributedBody = \"This is the first, not the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = \"The First Note\";\n})\n)}";
}}
-- something happened with core data --
NSConcreteNotification 0x61000004dc50 {name = NSManagingContextWillSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>}
-- something happened with core data --
NSConcreteNotification 0x61000024c870 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    inserted = "{(\n    <testwiki.Note: 0x6100000a8fa0> (entity: Note; id: 0x610000228e00 <x-coredata://18C6EA07-F369-4289-B333-53326C2B9DFE/Note/p226> ; data: {\n    attributedBody = \"This is the first, not the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = \"The First Note\";\n})\n)}";
    updated = "{(\n)}";
}}
loadNote
Optional("second")
Optional(New note{
})
-- something happened with core data --
NSConcreteNotification 0x610000053a10 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    inserted = "{(\n    <testwiki.Note: 0x6100000a9a80> (entity: Note; id: 0x6100002298c0 <x-coredata:///Note/tBCC61422-BDB8-44EB-A1A0-D32126C892355> ; data: {\n    attributedBody = \"New note{\\n}\";\n    body = nil;\n    title = second;\n})\n)}";
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
}}
-- something happened with core data --
NSConcreteNotification 0x61800005cbc0 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
    updated = "{(\n    <testwiki.Note: 0x6100000a9a80> (entity: Note; id: 0x6100002298c0 <x-coredata:///Note/tBCC61422-BDB8-44EB-A1A0-D32126C892355> ; data: {\n    attributedBody = \"This is the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = second;\n})\n)}";
}}
-- something happened with core data --
NSConcreteNotification 0x618000240d50 {name = NSManagingContextWillSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>}
-- something happened with core data --
NSConcreteNotification 0x61800005d970 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    inserted = "{(\n    <testwiki.Note: 0x6100000a9a80> (entity: Note; id: 0x61800003ac20 <x-coredata://18C6EA07-F369-4289-B333-53326C2B9DFE/Note/p227> ; data: {\n    attributedBody = \"This is the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = second;\n})\n)}";
    updated = "{(\n)}";
}}
-- something happened with core data --
NSConcreteNotification 0x618000242310 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
    updated = "{(\n    <testwiki.Note: 0x6100000a9a80> (entity: Note; id: 0x61800003ac20 <x-coredata://18C6EA07-F369-4289-B333-53326C2B9DFE/Note/p227> ; data: {\n    attributedBody = \"This is the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = second;\n})\n)}";
}}
-- something happened with core data --
NSConcreteNotification 0x618000242f40 {name = NSManagingContextWillSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>}
-- something happened with core data --
NSConcreteNotification 0x608000046240 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    inserted = "{(\n)}";
    updated = "{(\n    <testwiki.Note: 0x6100000a9a80> (entity: Note; id: 0x61800003ac20 <x-coredata://18C6EA07-F369-4289-B333-53326C2B9DFE/Note/p227> ; data: {\n    attributedBody = \"This is the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = second;\n})\n)}";
}}
about to segue to editNote
with title
Optional("The First Note")
Optional(This is the second.{
    NSFont = "\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\"";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0";
})
------------------------
loadNote
Optional("The First Note")
Optional(This is the second.{
    NSFont = "\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\"";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0";
})
-- something happened with core data --
NSConcreteNotification 0x618000241aa0 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x6180001c01e0>; userInfo = {
    managedObjectContext = "<NSManagedObjectContext: 0x6180001c01e0>";
    updated = "{(\n    <testwiki.Note: 0x6100000a8fa0> (entity: Note; id: 0x610000228e00 <x-coredata://18C6EA07-F369-4289-B333-53326C2B9DFE/Note/p226> ; data: {\n    attributedBody = \"This is the second.{\\n    NSFont = \\\"\\\\\\\"Helvetica 12.00 pt. P [] (0x610000247e90) fobj=0x101b11ca0, spc=3.33\\\\\\\"\\\";\\n    NSParagraphStyle = \\\"Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\\\\n    28L,\\\\n    56L,\\\\n    84L,\\\\n    112L,\\\\n    140L,\\\\n    168L,\\\\n    196L,\\\\n    224L,\\\\n    252L,\\\\n    280L,\\\\n    308L,\\\\n    336L\\\\n), DefaultTabInterval 0, Blocks (\\\\n), Lists (\\\\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation YES, HeaderLevel 0\\\";\\n}\";\n    body = nil;\n    title = \"The First Note\";\n})\n)}";
}}

其他注意事项:我正在使用重写的 keyDown 函数的子类 NSTextView 中查看 command-l。

编辑:我忽略了指出,如果我创建一长串音符,使用 command-l 从一个到下一个,当我返回查看时,该链中的每个音符都将具有相同的音符主体他们。

【问题讨论】:

  • 问题是self.note?.attributedBody=noteBody.textStorage吗?所有的属性都指向同一个 textStorage。
  • 就是这样!所以我不得不将 saveNote() 中的这一行: self.note?.attributedBody=noteBody.textStorage 更改为这些: let attributesBody = NSAttributedString(attributedString: noteBody.textStorage!) self.note?.attributedBody=attributedBody 如果你写一个回答,我会接受的。

标签: macos swift core-data


【解决方案1】:

所有属性化的Bodies都指向同一个textStorage。

改变

self.note?.attributedBody=noteBody.textStorage

self.note?.attributedBody = NSAttributedString(attributedString: noteBody.textStorage!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 2015-08-31
    相关资源
    最近更新 更多