term タグ別の記事一覧

macOSでGhostscriptをビルドする

 PostScriptやPDFを扱う際にほぼ必ず出てくるGhostscriptですが、公式サイトにはmacOS向けのバイナリが見当たりません。ということで、自前でビルドする手順 のメモです。

 なお、GhostscriptのmacOS向けバイナリとしてはRichard Koch氏によって配布されているものもあるのですが、最新版はHigh Sierra以降向けでSierra環境では利用できません。また、brewコマンドでもインストールできますが、個人的にbrewコマンドをあまり使いたくない、という理由で自前でビルドしています。

 Ghostscriptのソースコードは、公式サイトのダウンロードページから入手できます。ダウンロード後、適当なディレクトリに展開しておきます。

必要な依存ライブラリ

ビルドには以下のライブラリが必要です。

 このうち、libpng、lcms、jbig2decはダウンロードしたアーカイブを展開して./configure;make;make installというおなじみの手段でビルド&インストールが行えます(一部はfreetypeとlibjpegのようにソースツリー内に展開するだけで一緒にビルドできるようなのですが未確認)。

 freetypeとlibjpegについては、アーカイブをGhostscriptのソースコードを展開したディレクトリ(ソースツリーのトップディレクトリ)に展開し、そのディレクトリ名を「freetype」および「jpeg」に変更しておくことで自動的にビルドされます。

 また、gxpsのビルドにはJPEG XRのサポートが必要なようなので今回は無効にしました。ということでGhostscript自体のconfigureオプションは次のようになります。

$ ./configure --without-xps

 あとはmakeコマンドを実行するとgsコマンドがビルドされ、「make install」で/usr/local/bin以下にgsコマンドがインストールされます。

 また、libgsが必要な場合、「make so」コマンドを実行するとバイナリがビルドされ、「make soinstall」でそれらをインストールできます(詳しくはbase/unix-dll.makを参照)。

macOSアプリ開発でStoryboard+Core Dataを使うときのハマり話

 ふと思い立って久しぶりにmacOSアプリ開発を始めて見たのだが、Core Dataで管理しているデータを(CocoaBindingを使って) Storyboardを使って作った画面上に表示するところでハマったうえにググっても情報を探すのが大変だったのでメモ。

参考文献

作業と疑問点

 Xcode(7.2.1)でOS Xの「Cocoa Application」を選択してテンプレートからプロジェクトを作成。このとき「Use Storyboards」、「Create Document-Based Application」、「Use Core Data」にチェックを入れておく。続いてAppleのCore Dataプログラミングガイドの「管理オブジェクトモデルの作成」に従ってオブジェクトモデルを作成する。

 さらにこのドキュメントでは「Core Dataスタックの初期化」を行うよう記されていて、NSManagedObjectContext、NSPersistentStoreCoordinator、NSManagedObjectModelの3つが必要と記述されている。しかし、初期化コードとしてDataControllerクラスの実装例もあるのだが、このオブジェクトをどのオブジェクトが所持すべきなのか(ビューなのかドキュメントなのか)が記載されていない。

 プロジェクト作成時に「Use Core Data」にチェックを入れておくと、ドキュメントの基底クラスとしてNSPersistentDocumentが使われるのだが、ドキュメントを見る限り、自動的にCore Data関連の初期化を行って「ready-to-use」のNSManagedObjectContextのインスタンスを提供すると書いてある。この解釈だと、自前でCore Dataスタックの初期化をする必要はなさそうである。

 「Core Data の使い方(1)」ページではViewController内でNSManagedObjectContextのインスタンスを作成し、ここでCore Dataの初期化を行っているのだが、本来Core Dataの管理はDocument(MVCにおけるModel)の仕事であるべきで、ViewController内でこの作業を行うのはよろしくないのではないか、という疑問があるし、前述の通りNSPersistentDocumentを利用する場合この処理は不要であるはずである。

 しかし、Documentが持つNSManagedObjectのインスタンスをArray Controllerに参照させる手段が分からない。DocumentにArray Controllerのoutletを作成できれば、そのオブジェクトのsetManagedObjectContextを使ってNSManagedObjectContextインスタンスを渡すことはできるのだが、StoryboardではDocumentにArray Controllerのoutletを作成することもできない。

 ちなみにArray Controllerを使ってTable ViewとArray Controllerをバインドしただけだと、Array ControllerにNSManagedObjectContextが関連付けられていないため「cannot perform operation without a managed object context」というメッセージが表示される。

解決法

 StackOverflowの「How do you bind a storyboard view to a Core Data entity when using NSDocument?」にそのものずばりの質問と回答があった。結論的には、まずDocument.swiftのmakeWindowControllers()の末尾に下記を追加する。

windowController.contentViewController!.representedObject = windowController.document

 これでView ControllerのrepresentedObjectがDocumentを参照するようになる。

 続いてArray ControllerのView Controllerで、Managed Object Contextで「Bind to」にチェックを入れ、「View Controller」を指定する。Model Key Pathには「representedObject.managedObjectContext」を指定する。以上で完了。ただ、このときModel Key Pathに「!」が表示されるのがちょっと気持ち悪い。

まとめ

  • 「Use Core Data」を選択してプロジェクトのテンプレートを作った場合、独自に初期化コードを書く必要は無い
  • DocumentからView Controllerにアクセスするのは面倒臭い

 なおこの辺の作業を行ったコードはhttps://github.com/hylom/ttune/tree/76d43fe476c24f064aee51b7748529aa82a309d1です。