2015-10-17 54 views
1

所以我想學習Swift,並且我確定我做錯了什麼,但我無法弄清楚可能是什麼。不尋常的核心數據行爲 - 保存另一個對象的效果?

我正在寫一個筆記記錄應用程序來幫助自己加快語言的速度。它具有表格視圖(由NSArrayController填充)。點擊表格視圖中的一個註釋會顯示一個視圖控制器,顯示該註釋的標題和正文。點擊添加按鈕將創建一個新的筆記管理對象,並將其傳遞給與用於編輯的視圖控制器相同的視圖控制器。

編輯筆記時,選擇某些文本並按下command-l的用戶可以創建一個標題等於所選文本的新筆記。

除了命令-l以外,一切都很好。這種行爲是最不尋常的,我敢肯定,這是我造成的。

它是這樣的:

  1. 創建註釋並填寫標題和正文。假設它被稱爲「第一」,而身體是「這是第一個,而不是第二個」。
  2. 選擇一些文本('second')並按下command-l。這將保存當前音符,創建一個新的託管對象,填充標題('秒'),並將其顯示在視圖控制器中。輸入正文('This is the second')
  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 
     } 
    }  
} 

創建第一個註釋:

enter image description here

按下Command-L鍵後,第一個音符被保存,第二注意創建:

enter image description here

保存了第二個音符(點擊完成)後,返回到表視圖,並點擊第一:

enter image description here

所以,試圖找出這是怎麼回事,我志願加入了managedObjectContext通知。我這樣做是在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)}"; 
}} 

其他說明:我會留意的命令-1的子類NSTextView與重載的keyDown功能。

編輯:我忽略了指出,如果我創建了一長串筆記,使用command-l從一個到下一個,當我回去看時,那個鏈中的每個音符都會有相同的音符體在他們身上。

+0

是問題'self.note?.attributedBody = noteBody.textStorage'?所有歸屬身體指向相同的文本存儲。 – Willeke

+0

就是這樣!所以我不得不改變saveNote()這一行: self.note .attributedBody = noteBody.textStorage 這些: 讓attributedBody = NSAttributedString(attributedString:noteBody.textStorage)? self.note .attributedBody = belongsBody 如果你寫了一個答案,我會接受它。 – Chris

回答

0

所有的權限都指向相同的文本存儲。

變化

self.note?.attributedBody=noteBody.textStorage 

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