NSTableViewの行ドラッグ&ドロップをやってみた

今回はNSTableView内の行をドラッグで移動させてみます。

やること

  1. ドラッグ元の行番号をPasteboardに保存する。
  2. ドロップされた時に、そのドロップを受け入れるかチェック。
  3. ドロップを受け入れたら、Pasteboardに保存していたドラッグ元の行番号を取り出して、ドロップ先と入れ替えるなど。

3では用途に応じて、移動元の行と移動先の行に対して自由に操作を行います。
今回は、移動元と移動先を「入れ替える」挙動にしてみました。

実装

NSTableViewDataSourceの以下3つを実装します。

1. ドラッグ元の行番号をPasteboardに保存する

func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
    // Pasteboardにドラッグ元の行情報を記録
    let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
    let item = NSPasteboardItem.init()
    item.setData(data, forType: draggingUTIType)
    pboard.writeObjects([item])
    return true
}

ペーストボードを使う所が少々トリッキーだなと感じました。

2. ドロップされた時に、そのドロップを受け入れるかチェック

func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
    // 今回は、同じTableViewからのDropのみを受け付ける
    guard let source = info.draggingSource() as? NSTableView, source === tableView else {
        return []
    }    
    return .move
}

例えば、別のウィンドウからファイルをドロップするような場合もここに入ります。 ファイルのドロップを受け入れたい時、または受け入れたくない時は、ここで許可や拒否をします。

  • .moveを返す:ドロップを受け入れる
  • []を返す:ドロップを受け入れない

NSDragOperation

今回は「移動」させたいのでNSDragOperation.moveを返しています。 NSDragOperationには、他にも.copyなどの操作があるので、移動以外にも使えるようです。(試していません)

3. ドロップを受け入れた後の処理

func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
    // ドラッグされたアイテムのUTI typeを確認
    guard let item = info.draggingPasteboard().pasteboardItems?.first?.data(forType: draggingUTIType) else {
        return false
    }
    // Pasteboardに記録しておいたドラッグ元の行Noを取り出し
    guard let sourceRowIndexes = NSKeyedUnarchiver.unarchiveObject(with: item) as? IndexSet, let from = sourceRowIndexes.first else {
        return false
    }

    // ... 入れ替えの処理など ...
    
    return true
}
  • ドラッグされたアイテムのUTIを確認して整合性チェック
  • Pasteboardに記録していたドラッグ元の行番号を取り出し

などしています。

ここではドロップ先の行番号が取得できるので、移動元と移動先の行番号を使ってデータの入れ替えなどを実装できます。

UTI

今回初めてUniform Type Identifiersの事を知りました。

サンプルではpublic.dataを指定しました。(誤っているかもしれません)

サンプル

以前にNSTableViewを試したサンプルに、ドラッグで行を入れ替えるコードを追加しました。

github.com

以上です!

NSTableViewをCocoa Bindingsで使ってみた

TableViewにデータを表示するためにCocoa Bindingsを初めて使ってみたので手順をメモしておきます。

環境

はじめに

ViewControllerにTableViewを設置しておきます。

f:id:takopomm:20170405151155p:plain

こんな感じです。

1. Array Controllerを設置

f:id:takopomm:20170405151356p:plain

Array ControllerをSceneの中に追加します。

f:id:takopomm:20170405151403p:plain

@IBOutletでViewControllerに接続しておきます。

class ViewController: NSViewController {
    @IBOutlet var arrayController: NSArrayController!

2. モデルを書く

TableViewに表示したいパラメータを持つモデルを定義します。

例えば、「No」「名前」「年齢」などなど…自由に。

3. Array Controllerにコンテンツを追加

先ほどIBOutletで接続したArray Controllerに、TableViewに表示したいパラメータを持つモデルデータを追加します。

arrayController.content = [もでる1, もでる2, もでる3, ...]

という感じです。

4. Storyboardの設定

4.1 Array Controller

Array Controllerを選択した状態で、Attributesの設定項目Object Controllerを編集します。

f:id:takopomm:20170405151707p:plain

  • Class Name: 先ほど定義したモデルのクラス名
  • Keys: モデルのパラメータ名を+から追加

f:id:takopomm:20170405151717p:plain

このような感じにしておきます。

4.2 Table View

Table Viewを選択した状態で、Bindingの設定項目Table Content - Content を編集します。

f:id:takopomm:20170405152031p:plain

  • Bind to Array Controller: チェックをONにする
  • Controller Key: arraygedObjectsのままにしておく

4.3 Table View Cell

Table View Cellを選択した状態で

f:id:takopomm:20170405152516p:plain

Bindingの設定項目Valueを編集します。

f:id:takopomm:20170405152523p:plain

  • Bind to Table Cell View: チェックをONにする
  • Controller Key:空欄のまま
  • Model Key Path:objectValue.xxx

Model Key Pathxxxの部分には、自分で定義したモデルの、表示したいパラメータ名を指定します。 上記の例ではnumberというパラメータを指定しています。

パラメータ名だけを指定してもダメなようです。objectValueが必要でした。

すべてのTable View Cellに設定する

TableViewのカラムが複数ある場合は、すべてのTable View Cellに対して、4.3のようにモデルのパラメータ名を指定しておきます。

以上で準備完了です。

5. 実行

f:id:takopomm:20170405152838p:plain

表示できました!

TableViewDataSourceを指定しなくても、データを表示できる所がいいですね。

ハマったところ

Table View CellModel Key Pathに何を設定したらよいか分からず色々と試していたら、Storyboardのビルドが一向に進まず、しかしエラー内容は特に表示されず、、という状況になってしまい困りました。。

サンプル

上記の実装だけですが、GitHubに置きました。

github.com

Nexus 5Xにfactory imageを焼こうとした時の試行錯誤帳

factory imageを焼こう

Android OのDeveloper previewが出ましたね。
私は普段iOSをメインに使っていることもあり、Androidはちょっと冒険しやすい環境なので早速入れてみました。
バックアップを取る必要がある人は、factory imageを焼く前にバックアップを完了させておきます。私は特に何もせず始めてしまいました。(そしてすべてのデータがきれいさっぱりなくなりました!)

インストールの際に詰まったこと

端末がロックされているためインストールに失敗していました。

解決法

Androidの設定画面でOEMロックを解除してから、fastbootモードを起動、端末のロックを解除してからインストールします。

インストール手順

factory imageを手持ちの端末にインストールする手順を書き残しておきます。

環境

  • Nexus 5X
  • Android 7.0
  • Mac OSX 10.11
  • adbコマンドはすでに使える状態であることを想定しています。

手順

1: Nexus 5X用のfactory imageをダウンロードしてくる

2: Nexus 5XとPCをUSBで接続

3: Nexus 5Xの設定-開発者向けオプション-OEMロック解除をONにしておく

4: Nexus 5Xをfastbootモードにする

$ adb reboot bootloader

上記を実行して、Nexus 5Xをfastbootモードで起動させます。

5: 端末のロックを解除する

fastbootモードになると、ドロイド君のお腹がパカッと開かれてる画面になると思います。(ちょっと可愛い…!)
この画面下部の方に、

DEVICE STATE - locked

と表示されている場合は、端末がロックされている状態です。
この状態ではインストールできないので、以下のコマンドを実行して、端末のロックを解除します。

$ fastboot flashing unlock

すると、ロックを解除するか確認する画面が端末に表示されます。

「Yes」を選択しようと画面をタップしても反応しないです。
端末右横の「音量ボタン」を押すと、カーソルが動きます。
Yesにカーソルが合ったら、「電源ボタン」を押すと、ロック解除が実行されます。

ロックが解除されると、

DEVICE STATE - unlocked

と表示されます。

6: シェルを実行する

ダウンロードしたfactory imageのフォルダの中に、flash-all.shがあるので、これを実行します。

$ ./flash-all.sh

(↑カレントディレクトリがfactory imageのフォルダな状態で実行しています)

すると、色々と実行されていき、OSがインストールされます。

以上です!

Geek Women Japan 2016 に子どもを連れて行ってきた話

昨年11月に開催された、Geek Women Japan 2016に行ってきた時の振り返り話です。

eventdots.jp

しかしもう既に4ヶ月も過ぎてしまっておりますが。。
(明日開催されるミニカンファの前に何とか投稿したかった…!)

とてもありがたい事に、このカンファレンスでは託児所を用意してくださっているということで、まだオムツもはずれていない子ども3歳と一緒に行ってきました。(小声:パパが快く子守をしてくれればよいのになぁと思いつつ)

託児を利用するか悩みました

このカンファレンスにはどうしても行きたかったので、夫に何とかお願いするか託児を利用させてもらうか、ギリギリのギリギリまで悩んだ結果、託児を利用させてもらう事に決めました。が、その選択をして本当に良かったです。

実は当日の朝も、託児を利用することに対して妙な罪悪感のようなものを持っていて(←この気持ちはお母さんあるあるかなと思いますが…)、

「託児してまで参加してよいものか…」「私はダメなお母さんなのでは…」「やっぱりキャンセルしようか…」

とずっと葛藤していましたが、「ええいもう行ってみるだけ行ってみよう!」とモヤモヤをえいと振り払って出発しました。

いざ託児のお部屋へ

そして託児室にお邪魔してみると、午前中は我が子一人だけだったようで、 「あっ…なんだかとても申し訳ない…」と内心滝汗をかきました。。
たった一人のために保育の方々が来てくださったと思うと、非常に申し訳ない気持ちでいっぱいに。。

午前のセッションは少し早めに終わり、お昼の時間がゆったり取れたので、子どもと一緒に代々木公園に行きました。
この日はとてもお天気が良かったです。
青空の下、持参したお弁当を食べて、どんぐりを拾い、のんびりお散歩してから戻りました。

午後からは託児の方が他にもいらっしゃって、室内がとてもにぎやかに! 「あぁ、よかったー…」と正直ホッとしたことを覚えています。

ぬいぐるみを頂きました

託児室では、Salesforceのキャラクター(アストロくん?)のぬいぐるみをいただきました。今でも「タヌキしゃん」と呼び可愛がっています。
特にしっぽの部分がふわふわしているのが気持ち良くてお気に入りのようです。
しっぽをなでなでしながら寝付く…という、なんとも素敵な入眠アイテムとなっております。
肌触りが良いぬいぐるみ、最高!

子どもを連れて参加すること

子はまだ3歳なので理解できていないとは思いますが、こういった場に少しでも慣れ親しんでもらえたら、お母さんは嬉しいなぁと思っています。
(昨年夏のMakerFairも、私がどうしても行きたかったので連れて行きました)
(その時は早々にぐずり出してしまい、ほとんど見れずに終わりましたが…)

こういった託児サービスを無料で提供して下さることは本当にありがたかったです。そして休日開催であったことも。 未就園児を育てている私にとっては、この2点のお陰で、イベント参加への敷居は格段に下がりました。

託児は有料でも利用したいです。(ですが千円程度なら…!す、すみません…)

じっと座って静かにお話を聴けるくらいの年齢になったら、一緒に聴講してみたいなぁとも思いました。(個人的な夢です)

最後に

託児所を手配してくださったスタッフの方々。
お昼の時間には「お子さまと一緒にお外に出られても良いですよ」と柔軟に快く対応してくださった託児室の方々。

本当にどうもありがとうございました。とてもとても、感謝しております。

昨年は仕事と育児とアレコレ悩みすぎて自ら荒波にざぶーんと飲み込まれていたような時期がありましたが、GeekWomenJapan2016でプラスのエネルギーを沢山もらったので心の元気が復活しました。参加して本当に良かったです!

明日のミニカンファレンスも楽しみにしています。

Swiftで色のenumを作ってみる

CGColorのenumを作ってみようと思いました。

CGColorのenumを作ってみる

色の定数を作っているところが気持ち悪いというか…!
もうちょっと何とかならないかなと考え中ですが、一旦出力しておきます。

fastlaneでipaを作るだけのlane

fastlaneを使ってAdHocの.ipaを作るだけのlaneを書いた時のメモです。

環境

  • Xcode: 8.2.1
  • Ruby: 2.2.3
  • fastlane: 2.13.0
  • gym_version: 2.13.0

fastlane initが無事に済んだ後の状態を想定しています。

AdHocのipaを作るだけのlane

fastlane_version "2.13.0"
default_platform :ios

platform :ios do
  before_all do
    # どのlaneでも実行する前に必ずやること
  end

  # ipaを作るだけのlane
  lane :make_ipa do
    gym(
      workspace: "プロジェクト名.xcworkspace",
      configuration: "Debug",
      scheme: "プロジェクト名",
      clean: true,
      include_bitcode: false,
      output_directory: "./build",
      output_name: "プロジェクト名.ipa",
      export_method: "ad-hoc"
    )
  end

  after_all do |lane|
    # どのlaneでも実行が終わった後に必ずやること
  end

  error do |lane, exception|
    # エラーが起きた時にやること
  end
end

ここではmake_ipaという名前のlaneにしましたが、好きな名前を付けましょう。

AdHocビルドにしたかったので

  • export_method: "ad-hoc"
  • configuration: "Debug"

という設定にしました。

include_bitcode

プロジェクトでENABLE_BITCODENOにしている都合で一応明記してみました。(でも不要かもしれない)

output_name

今回はプロジェクト名.ipaということにしました。どんな名前でもOK。

output_directory

.ipaを出力するディレクトリを指定できます。
好きな場所を指定しても良いし、記述しなくてもOK。(指定なしの場合はプロジェクト直下に出来上がります)

laneを実行する時

$ fastlane make_ipa

実行したいlaneの名前を指定します。

つまずいた事

シェルの環境設定に問題がありビルドエラー

ビルド時に以下のようなエラーメッセージが出てしまいました。

 Exit status: 1
 Your shell environment is not correctly configured
 Instead of UTF-8 your shell uses US-ASCII
 Please add the following to your '~/.bashrc':

        export LANG=en_US.UTF-8
        export LANGUAGE=en_US.UTF-8
        export LC_ALL=en_US.UTF-8

 You'll have to restart your shell session after updating the file.
 If you are using zshell or another shell, make sure to edit the correct bash file.
 For more information visit this stackoverflow answer:
 https://stackoverflow.com/a/17031697/445598

.bashrcに、

export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8

これらを追記する必要があるということでした。

なので、.bashrcに追記して、

$ source .bashrc
$ exec -l $SHELL

.bashrcを読み込み直して(これだけではまた同じエラーに見舞われたので)、シェルを再起動させてから、再びfastlane make_ipaを実行しました。

すると先ほどのエラーは消え、無事に.ipaが作成できました!

参考

fastlaneを使い始めるまでにつまずいた事メモ

前置き

  • 普段Rubyを使っておらず自分がどんなRuby環境でいるか忘れている

fastlane initでエラーになった

$ fastlane init
Ignoring xcodeproj-0.17.0 because its extensions are not built.  Try: gem pristine xcodeproj-0.17.0
/Library/Ruby/Gems/2.0.0/gems/bundler-1.13.1/lib/bundler/rubygems_ext.rb:45:in `full_gem_path': uninitialized constant Bundler::Plugin::API::Source (NameError)

一旦、自分のRuby環境がどうなっているのか見直すことにしました。

rbenvを整える

Homebrewを使っています。
しばらくHomebrewをupdateしていなかったので、まずはupdateから。

$ brew update

無事にupdateが済んだので、rbenvを入れます。

$ brew install rbenv
Error: rbenv-0.4.0 already installed
To install this version, first `brew unlink rbenv`

以前にrbenvを入れていたようでalready installedと言われてしまいました。(すっかり忘れている…)

次はruby-buildをupgradeします。

$ brew upgrade ruby-build

こちらはもりもりと更新された。

Rubyのバージョンを確認

$ rbenv versions
  system
* 2.2.3 (set by /Users/なまえ/.rbenv/version)

ちゃんと設定されていそうでしたが、ruby -vで確認してみると、

$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin15]

思ってるのと違う…。システムの方が選択されている様子。

$ rbenv init
# Load rbenv automatically by adding
# the following to ~/.zshrc:

eval "$(rbenv init -)"

.zshrcに追記が必要との優しい案内が表示されています。(私はzshを使っているため)

.zshrc設定

.zshrcを開いて中身を確認すると、確かにeval〜の記述がなかったので追加します。

eval "$(rbenv init -)"

保存したら読み込み直します。

source ~/.zshrc

そして再度Rubyのバージョンを確認すると、

$ ruby -v
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin15]

やった!!

これでrbenvの環境が整いました!

一応、どこを見ているのか確認してみると

$ which ruby
/Users/なまえ/.rbenv/shims/ruby

ちゃんとrbenvを見ている様子!

gem install fastlane

これまではgem installすると、Permissionが云々と怒られてはsudo gemなどして、それでも失敗する様な事が多かったのですが、問題なくinstallできるようになりました。

$ gem install fastlane

無事にfastlaneをインストールすることができました。
その後、$ fastlane initも問題なく動作しました。よかった!

参考