3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NSTreeControllerとCoreDataのバインディング

Last updated at Posted at 2019-10-22

この記事は、macOS Catalina 10.15、Xcode 11.1で作成し、
macOS Big Sur 11.1、 Xcode 12.3で検証しています。

初心者ですが、macOSでCoreDataアプリを開発しようとしています。
NSTreeControllerの使い方を調べて試行錯誤した結果をメモしておきます。

新規プロジェクトの作成

新規にmacOSのアプリを作成します。

Project Name: NSTreeControllerTutorial
User Interface: Storyboard
Use Core Dataにチェックを入れます。

プロジェクトファイルの保存場所は、「書類」以外が良さそうです。
今回は関係ありませんが、SwiftUIのチュートリアルを試していたときに原因不明のエラーが出ました。

最初に表示されるTargetsの内容で、Infoタブを選択して、次のKeyの値をNOに変更します。

Key Value
Application can be killed immediately when user is shutting down or logging out NO
Application can be killed to reclaim memory or other extraordinary circumstances NO

これがYESのままだと、アプリ終了時にCore Dataの変更内容が保存されないようです。

ViewControllerにmanagedObjectContextのプロパティを作成

StoryboardでNSTreeControllerからバインドするためにViewController.swiftにmanagedObjectContextのプロパティを作成します。
ついでに、名前昇順でソートするためのSortDescriptorも併せて作成しておきます。
これらのイニシャライザも作成します。

ViewController.swift
    // MARK: - Core Data
    
    @objc let managedObjectContext: NSManagedObjectContext
    
    @objc let sortByName: [NSSortDescriptor]

    required init?(coder: NSCoder) {
        self.managedObjectContext = (NSApp.delegate as! AppDelegate).persistentContainer.viewContext
        
        self.sortByName = [NSSortDescriptor(key: "name", ascending: true)]
        super.init(coder: coder)
    }

CoreDataのModelを作成

Person Entityを作成します。

Attribute Type
name String
Relationship Destination Inverse Type
children Person parent To Many
parent Person children To One

001.jpg

Storyboardに部品を配置

Storyboardに部品を配置します。

  • Source List
  • Outline View
  • Tree Controller
  • Push Button x3

動作の違いを見るために、Source ListとOutline Viewの両方を配置しました。

002.png

NSTreeControllerの設定とバインディング

Attributes inspector

Key Value 備考
Children children relationshipsのchildren
Mode Entity Name
Entity Name Person
Fetch Predicate parent == nil relationshipsのparent
  • Prepares Content
スクリーンショット 2019-10-22 15.07.45.png

Bindings inspector

Bind to Model Key Path
Managed Object Context View Controller managedObjectContext
Sort Descriptor View Controller sortByName
スクリーンショット 2019-10-22 15.15.13.png

Outline Viewの設定とバインディング

一つ目のTable ColumnのValueにTree Controllerをバインドします。
Headerで昇順・降順を切り替えないのなら、Value Key Pathのバインドは空欄で良さそうです。
今回は、昇順・降順を切り替えないので、Create Sort Descriptorのチェックを外しておきます。

  • Create Sort Descriptor

なお、Value Key Pathをnameとバインドした上でCreate Sort Descriptorにチェックを入れておくと、実行時にタイトル行をクリックして昇順・降順を切り替えることができます。ただし、Tree ControllerのSort Descriptorsのバインディングを行っているとエラーが生じるようです。

スクリーンショット 2019-10-22 15.21.34.png

View Basedなので、直下のL Table View CellをTable Cell ViewのobjectValue.nameにバインドします。
nameを直接入力したいので、Conditionally Sets Editableにチェックをいれておきます。

  • Conditionally Sets Editable
スクリーンショット 2019-10-22 15.29.35.png

Push Buttonのバインディング

ボタンは、Tree ControllerのAdd:、Add Child:、Remove:とバインドします。
Removeボタンは、EnabledをTree ControllerのcanRemoveともバインドしておくといいですね。

実行

スクリーンショット 2019-10-22 15.45.45.png

とりあえず、ここまで動作しました。
アプリを終了して再起動すると、保存されたデータが名前順でソートされて表示できています。
2列目は設定を加えていないので、View Basedの初期表示ですね。

Source Listは、同様にバインドするだけでは表示できなくて、Outline View Delegateのfunctionを設定する必要があります。

Source Listのバインディング

とりあえず、Source Listも同様にTable ColumnとTable View Cellのバインディングを設定します。

スクリーンショット 2019-10-22 16.45.04.png スクリーンショット 2019-10-22 16.49.34.png

実行してみると、一応動作はしているのですが、文字が表示されていません。

スクリーンショット 2019-10-22 16.51.56.png

NSOutlineViewDelegateの設定

事前準備として、nameを表示したいTable View Cellを含むTable Cell Viewのidentifierを確認しておきます。
デフォルトで"DataCell"となっていました。
スクリーンショット 2019-10-22 18.48.39.png

そこで、View ControllerにNSOutlineViewのデリゲートメソッドを追加します。
せっかく覚えたので、extensionで追加します。

ViewController.swift
extension ViewController: NSOutlineViewDelegate {

    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
        return outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("DataCell"), owner: self)
    }
    
}

デリゲートメソッドなので、Source ListのdelegateをView Controllerと接続する必要があります。
スクリーンショット 2019-10-22 18.56.34.png

実行2

きちんと表示されました。これで完成!
スクリーンショット 2019-10-22 18.59.45.png

参考としたサイト

記事作成に当たり、次のサイトを参考としました。

StoryboardでのManagedObjectContextとのバインディング
macOSアプリ開発でStoryboard+Core Dataを使うときのハマり話

NSTreeControllerの使い方サンプル
The simplest NSTreeController example

Source Listの表示のためのデリゲートメソッド
Binding view-based NSOutlineView to Core Data

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?