【Swift】NSTableViewにセルが追加できない原因はビューにあるかも?

先日、NSTableViewで作ったテーブルビューにセルを追加する方法を紹介しました。

 

その中で軽く触れたのですが、この記事で紹介した方法は同一ビューの中でしか機能しません。

別のビューからセルを追加するとエラーになるので、今回は別のビューからでもNSTableViewにセルを追加する方法を紹介します。

はじめに

 

前回同様、今回の記事でもSwiftとXcodeを使用しています。

インストールなどについては触れませんので、あらかじめ済ませておいてください。

 

前回の記事を確認していない方は、先にこちらから確認しておきましょう。

今回作成するアプリケーションと前回の記事で紹介した内容がかぶっている場合、一部省略する可能性があります。

 

【Swift】テーブルビューにセルを追加するNSTableViewの使い方 - クリアメモリ

 

こちらの記事で、NSTableViewにセルを追加する方法を紹介してるのですが、別のビューから追加しようとするとエラーが発生します。

例えば、ポップオーバーしたウィンドウからセルを追加しようとするとエラーが発生してしまうんですよね。

 

そこで今回は、以下のような形でNSTableViewにセルを追加する方法を紹介します。

 

20170515140845

 

今回の流れ

 

今回の流れは以下のようになっています。

 

  1. ストーリーボードを作成
  2. ビューをpopoverで接続
  3. コードからNSTableViewの値を取得
  4. 別ビューからテキストの内容を取得
  5. NotificationCenterで通知
  6. 通知を受けたらNSTableViewを更新
  7. セルが追加される

 

このような順でストーリーボードやコードを作成していきます。

ではまず、ストーリーボードにTableViewや別のビューなどを配置していきましょう。

 

ストーリーボードを作成

 

今回作成するアプリケーションで必要になるオブジェクトは以下のものになります。

 

  • TableView (Cell Based)
  • Button (Popover)
  • View (Another View)
  • Label (Name and Age)
  • TextField (Text)
  • Button (Append)

 

では順番に作成していきましょう。

 

TableViewを配置

 

まずは、前回同様「TableView」をストーリーボード上に配置してください。

 

20170515140846

 

今回は「コラム数: 2」「ContentMode: Cell Based」で作成しました。

 

TableViewのTable Header Viewには「Name」と「Age」を指定しておきましょう。

ここで作成したコラムにそれぞれ「Identtifier」を設定する必要があります。

 

作成したコラムを選択した状態で、Identity inspectorを開いて「Identtifier」を以下のように編集してください。

 

20170515140853

 

20170515140854

 

これがないと後で紹介するコードで、入力が名前なのか年齢なのか判断できなくなります。

また、TableViewではデータソースを使用するので、dateSource接続しておいてください。

 

別のビューを呼び出すボタン

 

続いて、別のビュー(以下 > ビュー2)を表示するためのボタンを作成します。

 

今回は「+」と書かれたボタンをクリックすることで、ビュ-2がポップアップ表示されるようにしてみました。

( 設定方法はビュー2作成後に解説します)

 

20170515140847

 

ビュー2を作成

 

ビュー2では、名前と年齢を入力するウィンドウを表示させます。

以下の画像を参考にして、ビューを完成させてください。

 

20170515140848

 

NameとAgeに入力された文字列が、先ほど作成したTableViewのセルになります。

 

+ボタンとビュー2を接続

 

+ボタンをクリックした時にビュー2が表示されるようにするには「+ボタンからビュー2にセグエ」で接続してください。

 

20170515140856

 

ボタンからビューに接続すると「Action Segue」という項目が表示されるので、その中から「Popover」を選択しておきましょう。

 

20170515140855

 

このような表示になったかと思います。

ビュー2を表示する設定はこれだけです。

 

20170515140857

 

これでストーリーボードが完成しました。

アウトレット接続やアクション接続については、コードを書く時に一緒に説明します。

 

コードを書く

 

では実際にコードを作成しましょう。

今回は「ViewController」「Member」「AddMemberLiset」というクラスをそれぞれ作成してみました。

 

先に今回作成したコードを紹介した後で、順番に解説していきます。

 

ViewController -> TableViewを管理

import Cocoa

class ViewController: NSViewController, NSTableViewDataSource{

    @IBOutlet weak var tableView: NSTableView!

    var member =
        [
            Member(name: "Yamada", age: 21),
            Member(name: "Sato", age: 19),
            Member(name: "Suzuki", age: 25)
        ]

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(nCenter), name: NSNotification.Name("AddMember"), object: nil)
    }

    override var representedObject: Any? {
        didSet {}
    }

    // NotificationCenter >>>
    func nCenter(notification: Notification){
        let addMember = notification.userInfo?["member"]
        member.append(addMember as! Member)

        tableView.reloadData()
    }

    // tableview datasource >>>
    func numberOfRows(in tableView: NSTableView) -> Int {
        return member.count
    }
    func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {

        let columns = tableColumn?.identifier

        if columns == "Name"{
            return member[row].name
        }else if columns == "Age"{
            return member[row].age
        }

        return ""
    }
}

 

今回のコードはこのようになりました。

では順番に解説を確認してください。

 

解説

 

Point
ViewController ->
作成したTableViewの表示や追加後の更新、NotificationCenterなどを記述してあります。
Memberクラス ->
ViewControllerの配列memberに追加する値を初期化させるクラスです。

AddMemberList ->
TableViewに名前と年齢に入力された文字列を取得しセルを追加します。

 

ViewControllerの解説

 

まずはTableViewをアウトレット接続しています。

 

@IBOutlet weak var tableView: NSTableView!

 

続いて、配列memberの中に初期状態で表示する項目を追加しておきました。

これは空白でも構いません。

 

viewDidLoad( )ではNotificationCenterに通知を追加しています。

addObserver( )で通知の名前や、セレクタなどを指定する必要があり、NSNotification.Nameは後述するPostで設定した名前と同じにしてください。

 

NotificationCenter.default.addObserver(self, selector: #selector(nCenter), name: NSNotification.Name("AddMember"), object: nil)

 

nCenterでは通知を受けた時の処理を記述します。

 

// NotificationCenter >>>
func nCenter(notification: Notification){
  let addMember = notification.userInfo?["member"]
  member.append(addMember as! Member)
  tableView.reloadData()
}

 

先ほど同様、userInfo[ ]の文字列もNotificationCenter.default.postで設定したものと同じにしてください。

tableView( )では、先ほど設定したコラムのIdentifier (Identity) を判定しています。

 

let columns = tableColumn?.identifier
if columns == "Name"{
  return member[row].name
}else if columns == "Age"{
  return member[row].age
}
return ""

 

コラムのIdentityがNameなら…

コラムのIdentityがAgeなら…

 

Memberの解説

 

ViewControllerのMember( )では、名前と年齢をひとまとめにして配列に追加していました。

そのMemberをこのクラスで定義しました。

 

この記述がないと、ViewControllerはエラーになるので注意。

また、以下の画像にあるように「Target Membership」のプロジェクトにチェックが入っていることを確認してください。

 

20170515140859

 

※作成したプロジェクト名によって表示される内容は異なります。

 

AddMemberListの解説

 

最後にAddMemberListの解説になります。

このコードの中では、Appendボタンがクリックされたら「NotificationCenterに通知」を送るようになっています。

 

@IBAction func appendButton(_ sender: NSButton) {
  let nameString = nameText.stringValue
  let ageInt = Int(ageText.stringValue)
  if nameString != "" && ageInt != nil{
    let member = Member(name: nameString, age: ageInt!)
    NotificationCenter.default.post(name: NSNotification.Name("AddMember"), object: nil, userInfo: ["member": member])
    nameText.stringValue = ""
    ageText.stringValue = ""
  }
}

 

名前と年齢のテキストフィールドが空白ではない場合、ViewControllerに通知を送り、テーブルビューをリロードさせています。

このようにすることで、別のビューからでもテーブルビューを更新させることができました。

 

まとめ

 

今回紹介したように、テーブルビューに別のビューからセルを追加するには、NotificationCenterを使用することで実装できました。

これで、決まった内容のテーブルビューだけではなく、ユーザーが追加した項目を反映させることができますね。

 

とはいっても、保存処理を記述していないので、アプリを終了すると消えてしまいますが。

NSTableViewやNotificationCenterはとても便利なので、ぜひ活用してみてください。

 

 

ではまた。

過去にレビューしたアイテム