知らずに回る Run Loop にご用心

MacDev

CotEditor 2.1.6 リリース!

以前記事を書いて紹介したように(→ 2015.2.19)何年も愛用している OS X 用プレーンテキストエディタである CotEditor。最新バージョンの 2.1.6 がリリースされた。

→ CotEditor -Text Editor for OS X

変更点を見てみると:

いくつか前のバージョンから保存時にフリーズするという問題があったのだけど、ほとんどの人はこれで直ると思います。

...という自慢でした。😤

-[NSTask waitUntilExit] の罠

自慢するだけなのもあれなので、今回の問題を引き起こしていた原因を同じバグで悩んでいる開発者のためにメモしておく。

CotEditor ではファイルの読み書きに authopen というコマンドを使うような構造になっているのだけど、それを Cocoa から呼び出すために NSTask というクラスが使われている。保存するデータをそこに投げたあと、処理を待つために呼ばれていたのが -waitUntilExit というメソッド。

waitUntilExit という名前の通り、アプリケーションの処理を休んでコマンドが終了するのを待ってくれるものかと思いきや、ヘッダファイルのコメントを読むと罠があった。

// poll the runLoop in defaultMode until task completes

Run Loop が回るらしい。...ということはこの待ち時間の間、先にセットされていたタイマーの時間が来たらその処理が次々と割り込んでくることになる!

CotEditor の場合、ファイルの保存で authopen が処理をしている中、その処理を待つ間に自動保存のタイマーが発動してしまい、予期せぬタイミングでもう一つの保存が実行されてしまっていた。それが結果的にフリーズを引き起こしていたのだ。

対策は簡単で、このメソッドを使わず単純なループで待つようにすればいい:

while (task.isRunning) usleep(200);

Wait 処理を使うときはどんな仕組みで待っているのか注意しましょう。

記事編集画面に“Finder に表示”ボタンを追加 - ShowInFinder

Site

記事を書くモチベーションの 3 割ぐらいは記事編集画面の出来にかかっている。

以前のリニューアルのときにもちらっと見せたように(→ 2015.3.14)文章はすべてあのブラウザ上の画面で編集している。JavaScript ベースのエディタ CodeMirror を貼り付けてそこそこ快適になったと書いたのはその通りなのだけど、まだ不便なことが。

PHP で書かれたこの画面には添付するファイルを管理する機能がない。なので画像などを貼ろうと思ったら記事ごとに作成されるフォルダを Finder で開いて用意したファイルを入れるという作業をしている。Finder を使ったファイルの移動なんて大した作業ではないし、参考資料や元画像も同じ場所に入れておけるのでこの管理方法は便利なんだけど、Finder に切り替えてフォルダを探すのがとても面倒。これはなんとかしたい。

URL スキーム "file"

最初に試したのが、"file" という URL スキーム。フォルダへのパスを元に file:///Applications/ みたいなリンクを作って記事編集画面に置いておけば簡単に開くことができるはず。でもこのリンクをクリックするとわかるように、機能しない。

マシン上にテストの HTML ファイルを作って直接 Safari で開いた場合は動くので、たぶんセキュリティ上の問題(システム関係のファイルを開いてしまうような?)を避けるためにこんな仕様になっているのだろう。外部のページじゃなくて localhost へのアクセスでもダメ。localhost ぐらい有効になってくれればいいのに。

専用アプリケーションを用意

こうなったら自分で“Finder に表示”する URL スキームを用意してしまおう。Mac で好きな URL スキームを追加しようと思ったら専用のアプリケーションを作るのが早い。早速 ShowInFinder.app を書いた。

↑ 記事編集画面はこんな感じに。小さくてわかりにくいけど、カーソルのところのボタンを押すだけで Finder がフォルダを開いてくれる。便利になった!

役に立つ人がいるかどうかはわからないけどせっかく作ったので配布します。→ documents/ShowInFinder