NSTableViewを使って表形式のデータを表示する方法を説明します。

NSTableViewはUIKitのUITableViewに相当するクラスですが、UITableViewと異なり複数の列を表示することができます。

ここでは各行に本の情報(タイトルと出版社)を表示する簡単なプログラムを作成します。

以下具体的な手順を説明します。

プロジェクトの作成

macOSアプリケーションを作成します。Xcodeを起動しメニューから「File > New > Project」を選択します。

▲作成するアプリの種類を選びます。「macOS」の中にある「App」をクリックします。

▲プロジェクトの情報を入力します。

  • Product Name: プロジェクトの名前を入力。
  • Team: 開発チームを選択。
  • rganization Identifier: 組織の識別子を入力。
  • Interface: インターフェイスを構築するフレームワーク。Storyboardを選びます。
  • Language: 開発言語。Swiftを選びます。
  • Use Core Data: Core Dataを使用するかどうか。
  • Include Tests: テスト用のコードを追加するかどうか。

すべて入力したら「Next」ボタンをクリックします。プロジェクトを作成するフォルダを選び保存したら完成です。

画面の作成

プロジェクトが作成できたら「Main.storyboard」を選択します。

▲オブジェクトライブラリからTable Viewを選択してViewControllerにドロップします。

▲Table Viewをレイアウトします。サイズは任意ですがフレーム一杯のサイズに広げておくとわかりやすいと思います。オートレイアウトを利用し、Table Viewに四辺に制約をつけておきます。

次にテーブルビューの各列の識別子とタイトルを設定します。

▲Table Viewの中にある列のオブジェクト(最初はAutomaticTableColumnIdentifier.0というような名前になっています)を選択します。Identity Inspectorを開き、Identifierをそれぞれ「title」「publisher」と変更します。

▲さらにTable Viewのヘッダー部分をダブルクリックして、列の名前「タイトル」「出版社」に変更します。

ソースコードの作成

ソースコードを実装していきます。

まずアウトレットを作成します。アシスタントエディタを開いておきます。

▲Interface BuilderでTable Viewを選択し、ViewControllerのソースコードにCtrl+ドラッグします。名前は「tableView」とします。

ViewControllerにNSTableViewDataSourceとNSTableViewDelegateを実装します。NSTableViewDataSourceはテーブルにデータを供給する役割を担い、NSTableViewDelegateはテーブルで発生したイベントを処理します。

ViewController.swiftのソースコードは次のようになります。

import Cocoa

struct Book {
    var title: String
    var publisher: String
}

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    @IBOutlet weak var tableView: NSTableView!
    
    var books =  [Book]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
        books.append(Book(title:"できるAppKit", publisher: "海空出版"))
        books.append(Book(title:"わかるSwiftUI", publisher: "テック出版"))
        books.append(Book(title:"わかるUIKit", publisher: "テック出版"))
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    // MARK: - NSTableViewDataSource
    func numberOfRows(in tableView: NSTableView) -> Int {
        return books.count
    }

    // MARK: - NSTableViewDelegate
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        
        guard let identifier = tableColumn?.identifier else {
            return nil
        }
        guard let cell = tableView.makeView(withIdentifier: identifier, owner: self) as? NSTableCellView else {
            return nil
        }
        let book = books[row]
        if identifier == NSUserInterfaceItemIdentifier("title") {
            cell.textField?.stringValue = book.title
        } else if identifier == NSUserInterfaceItemIdentifier("publisher") {
            cell.textField?.stringValue = book.publisher
        }
        return cell
    }
}

実行結果は次の通りです。

各行の1列目にはタイトルが、2列目には出版社の情報が表示されます。

重要メソッド1: numberOfRows(in:)

データの行数を返すメソッドです。

    // MARK: - NSTableViewDataSource
    func numberOfRows(in tableView: NSTableView) -> Int {
        return books.count
    }

重要メソッド2: tableView(_:viewFor:row:)

各セルの情報を表示するViewを返すメソッドです。カスタムビューを使用することもできますが、ここでは標準のNSTableCellViewを使用しています。各列は引数のtableColumnのidentifierで区別することができます。

    // MARK: - NSTableViewDelegate
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        
        guard let identifier = tableColumn?.identifier else {
            return nil
        }
        guard let cell = tableView.makeView(withIdentifier: identifier, owner: self) as? NSTableCellView else {
            return nil
        }
        let book = books[row]
        if identifier == NSUserInterfaceItemIdentifier("title") {
            cell.textField?.stringValue = book.title
        } else if identifier == NSUserInterfaceItemIdentifier("publisher") {
            cell.textField?.stringValue = book.publisher
        }
        return cell
    }