根本的な解決ではないです。ワークアラウンドです(;・∀・)

Xcode8(ひょっとしたら7でもよく起こってたかも。忘れた)から、Xcodeで既存のワークスペース(.xcworkspace)を開こうとすると、エラーが出てXcodeごと落ちることがしばしば起こり困っておりました。

何度か再起動したり、別のプロジェクトを開いて作業しているうちに、落ちていたワークスペースも開けるようになったりしてたので目的のプロジェクトを開くのにすごい無駄な時間を使っていたのですが、先日どうやっても、とあるワークスペースが開けなくなりました。

なんとなくビルドの中間ファイルとか、検索結果とか、そういった一時ファイルが壊れていて開けなくなってる感じでしたので、ワークスペース(プロジェクト)のビルドファイルが置かれる場所を探した所、

~/Library/Developer/Xcode/DerivedData/

こちらと判明。

この下に <PROJECT_NAME>-enhhsyckyifnnoblvfuyvftsxwyp といったディレクトリ(後の文字列はたぶんランダム)ができているので、該当のプロジェクト名から始まるディレクトリを削除すれば起動するようになります。

ただ、あの時間のかかる Indexing | Processing files はやり直しですがw

やべぇ、ブログ書くのほぼ2年ぶりじゃねぇか...

写真.appが使えるようになって早速iPhotoから移行しようとしたのですができなくてしばらくハマったので書いときます。

私のMacBookはSSD 256GBしかないので写真は外付けHDDに置いてます。

写真.appを初期起動時に特に何も聞かれずに空の状態で起動してしまったので、そのせいだろうとネットを検索してみると、案の定外付けHDDの場合はOptionを押しながら写真.appを起動して、iPhoto Libraryフォルダを選択しないと行けないようです。

これでイケソウだなとやってみると...ファイル選択ダイアログでiPhoto Libraryフォルダが選択可能になってくれない。

ネットで検索し続けるもそれに対する解決方法が全く見つからず、全てOption押しながらアプリ起動しろとしか書いていない。

不満も特にないし諦めてiPhotoを使い続けようかな、と思い始めたのですが、ネット上のiPhoto Libraryを選びなおしているスクリーンショットをよく見てみるとフォルダにアイコンが付いている事に気付きました。よく見ると.photolibraryって拡張子も付いている。

まさかとは思った(iPhotoは普通にこのフォルダをダブルクリックしても起動するので)がiPhoto Library.photolibraryと拡張子をつけてみるとアイコンが付いた!

期待を込めて写真.appをOption押しながら起動してみると無事選択することができました。ε-(´∀`*)ホッ

まとめ

写真.appで移行元のiPhoto Libraryフォルダが選べない場合は、iPhoto Libraryフォルダに拡張子.photolibraryを付けてみて下さい( ˘ω˘)

随分前のエントリーの焼き直しですw

諸般の事情によりYosemiteにはまだしばらく上げられないためXcode6.2をもう少し使い続けないといけないのですが、手元のiPhoneをうっかりiOS 8.3にアップしてしまった。やおら開発中のアプリを実機転送しようとしたら

cannot find developer disk image in `/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport' for version `8.3'

↑はRubyMotionでの出力ですが、Objective-CやSwiftで普通に開発してる場合でもこのエントリーは役に立つはずです( ˘ω˘)

  1. Xcode6.3のインストーラをDevCenterからダウンロードします。
  2. dmgファイルをダブルクリックしてマウントします
  3. 下記コマンドを実行してiOS8.3のDeviceSupportファイルをXcode6.2の中にコピーします
sudo cp -r /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/8.3\ \(12F69\) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/

以上です。

Yosemiteに上げるまでこれで頑張りましょうヽ(´ー`)ノ

あまり褒めらた方法ではないのですが、処理を簡単にするためAFNetworkingでの通信を同期で行いたいことはありますよね。

AFNetworkingのNSOperationQueuewaitUntilAllOperationsAreFinishedを呼んでやればできるのかとおもいきや、どうも意味が違うらしい。

そこで簡単に思いつくGCDのSemaphoreを使ってコールバックが終わるまで待つようにしてみたところ...

client.getのところで実行がデッドロックしているようでコールバックブロックが呼ばれません。

APIのログを確認するとサーバにアクセスは来ています。

これ、結構ハマってしまい諦めて別の方法で実装しようかなと思ってたのですが「Are AFNetworking success/failure blocks invoked on the main thread?」を発見してcompletionQueueの存在を知ります。

たぶんここcompletionQueueが設定されていない場合、dispatch_get_main_queue()が使われるのでデッドロックするのだと思われます。

dispatch_get_global_queueとかdispatch_queue_createとかしたものをセットすれば良さそうです。

先ほどのRubyMotionのafmotionを介して実行したサンプルですとAFMotion::Client.buildのDSLブロックに

   :
  response_serializer :json
  completion_queue Dispatch::Queue.concurrent
end

とかできれば良かったのですが、ClientDSLクラスには定義されてないようです。(プルリクチャンスかw) ただ返されるclientAFHTTPRequestOperationManagerそのもののようなので使う前に設定してみます。

client.completionQueue = Dispatch::Queue.concurrent

EXC_BAD_ACCESSります。RubyMotionのDispatch::Queueオブジェクトは元のGCDオブジェクトそのものではないので当然か。Dispatch::Queue.concurrent.methodsでメソッドを見てみるとdispatch_objectなんてものがありますので、おそらくコレですね。

期待通りに動くようになりました( ˘ω˘)

ブログ全然書いてないので小粒ネタ放流しとく(・ω・)

アルバムを使うiOSのアプリを作っていると、色んなバリエーションのある程度の枚数の写真がアルバムに入っている状態じゃないと効率が悪いです。

最も簡単な方法はiOS SimulatorのSafariで写真共有サイトを巡って、表示している画像を長押しして「画像を保存」です。

iOS%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%20-%20iPhone%20Retina%20(4-inch)%20/%20iOS%207.0%20(11A465)
Uploaded with Skitch!

しかしネット上の他人の画像を使ってうっかりどこかにアップロードするなどミスも怖いので、自分の写真を使いたい。

もちろん自分の写真を写真共有サイトや自由になるWEBサーバにアップロードすれば同じことができますけど、イメージファイル自体は手元にあるのに面倒です。

イメージをドラッグしててたまたま見つけたんですが、iOS SimulatorはOSX上のファイルをドロップすると反応します!

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202013/09/21%2019:19
Uploaded with Skitch!

Skitchでスクリーンショットを取ったのですが(+)アイコンが消えてしまって反応しているの分からなくて残念(´・ω・`)

このままドロップするとSafariでfile://でOSXローカルのファイルが表示されます。

あとは画像を長押しして保存するだけ。

MotionCVというOpenCVRubyMotionから使えるようにするラッパーライブラリを細々と開発してます。

現状

ある程度、枠組みはできてあとはOpenCVのAPI郡をどんどんObjective-Cでラップしていけば良い状況なのですが、APIが山ほどあってこりゃ大変だぞと(笑)

そこで、サンプルで実際に動かしながら必要なAPIから少しずつメソッドを追加していってます。上から黙々と単純作業で増やしていくだけだと心が折れる(汗) いつかはやらなきゃいけないのですが...

マンガ風フィルタサンプル

OpenCVで画像変換と言えばマンガ風カメラですからw実装しながら必要なAPIを拡充していきました。

ネットを探せばOpenCVでマンガ風フィルタを実装している例がいくつか見つかりますが、ほとんどがC APIを使っていてMotionCVでラップするのが些か面倒です。

C APIも@watson1978さんが実装方法をコミットしてくれたのでできそうですが...

ビルドには困らなくなったので暫く放置していた「OS XとiOSのためのOpenCV環境構築ガイド」をパラパラめくっていたら最後にアプリを作ってみようという章でマンガ風フィルタがC++ APIで実装されていたのですよ!

OS XとiOSのためのOpenCV環境構築ガイド
酒井 雅裕 加藤 寛人
カットシステム
売り上げランキング: 329,757


ここに載っている例で必要となるAPIをMotionCVに実装して、ロジックをRubyMotionに書き換えたのがこちらです。

cartoonize.rb

実際にiPhone Simulatorで動かしてみると、こんなふうに変換されます。

お台場のガンダム(Ruby会議帰りw)

あさぎり

初号機

実機でも問題なく動きました。

ビルド方法

最後に、この興味深いwプログラムをビルド&実行する手順を説明しておきます。

まず、サンプルプログラムをcloneしてきます。

$ cd /path/to/work
$ git clone https://github.com/iwazer/motioncv-test.git
$ cd motioncv-test

vendorの下に私がForkしてあるOpenCVをcloneして、opencv2.frameworkをビルドします。

$ pushd vendor
$ git clone https://github.com/iwazer/opencv.git
$ cd opencv
$ rake build target=all
$ popd

buildはi386(Simulator)、arm7、arm7sの3プラットフォーム分行われますのでかなり時間がかかります。

@watson1978さんがビルド用のRake Taskを書いてくれたので随分楽になりました!(・∀・)

あとはRubyMotionでほのぼのrake!

$ rake

RubyMotionのREPLはシミュレータでアプリを実行しながら内部の状態を確かめられるので便利ですが、こういう風に書けばいいのかな?といったトライアンドエラーで実験するときに、Frameworkや外部ライブラリ中のクラスや定数がプログラム中で使っていないとREPLでは未定義となっていて残念です。

こういう実験の例

使っているライブラリの定義を全て列挙したソースを生成してやれば参照できるようになるに違いないと思ってRakeタスク作りました(・ω・)

https://gist.github.com/iwazer/6292291

RubyMotionのRakefileのおしりにコピペしてpreload=trueオプションを付ければ使えます。

$ rake preload=true

だがしかし、自動生成したソースのコンパイルに5分とかかかります!m9(^Д^)

@watson1978 さんによると、そのうち本体で対応してくれるようになるかも、という事ですので、それまで用です(笑)

OSXです。他のプラットフォームは試してません(・ω・)

例えばこんなディレクトリ構成で

$ tree .
.
├── a
│   ├── 1.rb
│   └── b
│       ├── 2.rb
│       ├── c
│       │   └── 3.rb
│       └── x -> ../../x
└── x
    └── y
        └── 4.rb

$ rvm use ruby-2.0.0-p247
$ ruby -e 'puts Dir.glob("a/**/*.rb")'
a/1.rb
a/b/2.rb
a/b/c/3.rb

ホントはa/b/x/y/4.rbも入って欲しい(・ω・)

StackOverflowにこんな事が書いてあった。

http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob

Dir.glob("**/*/**/*.rb")は、とてもいいかんじだけど、

$ ruby -e 'puts Dir.glob("a/**/*/**/*.rb")'
a/b/2.rb
a/b/c/3.rb
a/b/x/y/4.rb

$ ruby -e 'puts Dir.glob("a/b/**/*/**/*.rb")'
a/b/c/3.rb
a/b/x/y/4.rb

ここまではいいとして、次の場合はcの下が見つかって欲しい。

$ ruby -e 'puts Dir.glob("a/b/c/**/*/**/*.rb")'

次だと見つかるので。

$ ruby -e 'puts Dir.glob("a/b/c/**/*.rb")'
a/b/c/3.rb

次は惜しいけど重複して見つかる場合がある。

$ ruby -e 'puts Dir.glob("a/**{,/*/**}/*.rb")'
a/1.rb
a/b/2.rb
a/b/c/3.rb
a/b/2.rb
a/b/c/3.rb
a/b/x/y/4.rb


$ ruby -e 'puts Dir.glob("a/b/c/**{,/*/**}/*.rb")'
a/b/c/3.rb

uniqすれば期待通りの結果。

$ ruby -e 'puts Dir.glob("a/**{,/*/**}/*.rb").uniq'
a/1.rb
a/b/2.rb
a/b/c/3.rb
a/b/x/y/4.rb

$ ruby -e 'puts Dir.glob("a/b/c/**{,/*/**}/*.rb").uniq'
a/b/c/3.rb

MRIじゃないけどRubinusでこんなIssueを見つけた。
https://github.com/rubinius/rubinius/pull/2481

今(2013/08/21)からひと月前にmasterにマージされてます。ちょっと試す。

$ rvm install rbx -n master
$ rvm use rbx-head-master
$ ruby -e 'puts Dir.glob("a/**/*.rb")'
a/1.rb
a/b/2.rb
a/b/c/3.rb

あれ?変わらない(-ω-)

まぁRubinusでできたとしても実際には利用できないのでいいんですけど。

今のところベストプラクティスは

Dir.glob("**{,/*/**}/*.rb").uniq

これですかね?

新しく来た開発マシン(OSX Mountain Lionになった)に開発環境を構築しようとしたらGemfileに指定されているRMagickのバージョン2.13.1に対応するImageMagick 6.7.7-6がなぜかHomebrewでエラーとなり入らなかったので、良い機会だと(これを書いた当時)最新のRMagick 2.13.2、ImageMagick 6.8.6-3に変えてみました。

新開発機ではテストは綺麗に通って問題なく動いたのでステージング環境でも同じバージョンのImageMagickを更新してデプロイしてみたところJenkinsさんが定期実行しているテストがコケまくり( ゚д゚)

あろうことかすべてのテストがこけている。RMagickがImageMagickのライブラリが見つけられず起動すらしていない有り様でした。

どうやらOSXの環境では最新の組み合わせで実行可能なようですが、まだすべてのプラットフォームで動くわけではなさそう。

時期尚早ということで以前から使っているバージョンの組み合わせに戻して、新開発機の方を対応させることにしました。新開発機にImageMagick 6.7.7-6をどうにかして入れられればひとまずやり過ごせる。

なぜ入らなかったのか確かめるためにHomebrewのコマンド出力をverboseにして実行します。

この辺りは少し前に書いたHomebrewで複数のバージョンのパッケージをインストールして使い分けるを参照していただけると何をやっているかわかると思います。

$ cd $(brew --prefix) 
$ brew unlink imagemagick
$ brew versions imagemagick
6.8.6-3  git checkout 870d5e9 /usr/local/Library/Formula/imagemagick.rb
6.8.0-10 git checkout 321b293 /usr/local/Library/Formula/imagemagick.rb
6.7.7-6  git checkout 7d951fb /usr/local/Library/Formula/imagemagick.rb
  :
$ git checkout 7d951fb /usr/local/Library/Formula/imagemagick.rb
$ brew -v install imagemagick
  :

しばらく待ってるとエラーで終了。

  :
brew: superenv removed: -L/usr/X11/lib -O2
brew: superenv removed: -g -O2 -Wall
ld: library not found for -lXext
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [magick/libMagickCore.la] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [install] Error 2
  :

どやらX11のライブラリlibXextが見つからないようです。ただ、/usr/X11/libを確認してもちゃんと存在します。

ここで、少し前の行に表示されている見慣れないbrew: superenv removed...という行に気付きました。

homebrew superenvでググってみたところ、こちらのQiitaの記事「Homebrew の superenv」を発見。

実行時の環境変数 PATH は無視され、Homebrew によって再構築される
...
コマンド実行時に --env=std オプションをつけることで superenv を回避可能
...
ニッチなツールをインストールするために自分で Formula を書くとか、だいぶ昔に書かれた野良 Formula を使うときとか、そういう時に影響がでそうな話。

これじゃないっすか〜

$ brew install imagemagick --env=std

するっと入ったヽ(´ー`)ノ

前回からだいぶ時間が経ってしまいましたが、実際にRubyMotionからOpenCVを使えるようにしていきます(`・ω・´)

前回紹介したとおりOpenCVはiOS用のビルドもできるのでXcode/Objective-Cで開発する場合はCocoapodsを利用すれば非常に簡単です。

RubyMotionから通常のstaticライブラリ(Framework)を利用する際には、Framework内のC/Objective-Cのヘッダファイルから定数や構造体、Objective-Cのクラス情報などをビルド時にBridge Supportというファイルに出力して、RubyMotionのはそこに定義があれば呼び出せるようになります。

RubyMotionのビルドではC++は解釈できないのでBridge Supportを作るときに読み込むヘッダファイルはCまたはObjective-Cのヘッダファイルである必要があります。RubyMotionに気づかれないようにC++部分を覆い隠すラッパーを作成していきます。

まずは最小限のラッパーを実装して動かしてみるところまでを目標にします。

サンプルは画像をグレイスケールに変換するフィルタとします。実はOpenCV for iOSの使い方 -- Qiitaのパク...いやインスパイアされてます。

Matの変換関数はMotionCVというObjective-Cのクラスのクラスメソッドとして実装することにしました。

UIImage <=> cv::Matの変換も先ほどのサンプルをそのまま利用させていただいています。

cv::Matを直接見せないようにMotionMatというObjective-Cクラスでラップすることにします。

これをOpenCVのビルド環境に組み込むのですが、リポジトリを観察した結果modulesの中に置くのが良さそうです。modules/motionというディレクトリを作成して、他のmoduleに習って下記のようにソースを配備します。

modules/motion/
├── include
│   └── opencv2
│       └── motion
│           ├── MotionCV.h
│           └── MotionMat.h
└── src
    ├── MotionCV.mm
    └── MotionMat.mm

ヘッダファイルはビルドの設定が書かれているcmake/OpenCVModule.cmakeの中でパスがinclude/opencv2/${name}/*.hと指定されているため、ディレクトリ構成を変更するとframework/Headersに入って来ません。

続いてこれらを利用するサンプルプログラムを作っていきます。

表示する部分はRubyMotionで次のようになります。

ほぼ、先ほどのページのサンプルをMotionCV/MotionMatを使用してRubyMotionに書き換えただけです。

次にRakefileに最低限必要な設定です。

追加したiOSのFrameworkはOpenCVが内部で使用しているため必要です。また-lc++もOpenCVが内部で標準C++ライブラリを使用しているため必要となります。

vendor_projectの設定に見慣れないforce_loadというオプションを指定しています。これを指定しないとduplicate symbol ...というエラーがたくさん出てコンパイルできません。

Duplicate symbol error when linking AdMob SDK in RubyMotion -- StackOverflowにこの回避方法が載っていたのでやってみたら先に進めるようになりました(・ω・)ノ

さて、これでやっとうまくいくかと思いきや、まだクラスやメソッドが見つからないというエラーで終了します。確かにBridge Supportファイルを検索しても入っていません。

Bridge Supportファイルの生成はデフォルトではvendorプロジェクト(OpenCVの場合vendor/opencv2.framework)内の"*/.{c,m,cpp,cxx,mm,h}"にマッチする全てのファイルが対象になりますので、何もしないとOpenCVのC APIのヘッダファイル全てが対象になると思われます。

ところがOpenCVのC APIにはC++のテンプレート構造体やINLINEマクロが大量に含まれていて、ほとんど処理されず空振りしているようです。

エラーになるのならばわかり易かったのですが、どうやらBridge Support出力は無視して進むように見えます。おそらく使えるものだけでも簡単に使えるようにしようという対応かと想像します

少々面倒ですが、サンプルプログラムのRakefile内に対象とすべきヘッダファイルをリストすることにします。

さて、これでもまだうまく行きません(笑)ビルドは成功するも実行時にMotionCVやMotionMatのメソッドが見つからないといって落ちます。

ビルドされたスタティックライブラリをstringsコマンドでのぞいてみると確かに存在しないようです。

OpenCVのcmake/OpenCVModule.cmakeをもう一度よくみてみると、

  :
  file(GLOB lib_srcs     "src/*.cpp")
  :

こういう設定がありました。本来ならモジュール内のCMake設定ファイルを用意して変更すべきなのでしょうが、暫定的にここにsrc/*.mmを追加してビルドしました。

iPhoneSimulatorで動いた様子

長いこと試行錯誤した結果RubyMotionTokyo meetup#4で動かすことができるようになったので写真はその時のものです。

実はラッパープログラムの方にも自分では結構長い時間分からなかったミスがあったのを@watson1978さんが見つけてくれたのも大きかったですヽ(´ー`)ノ

OpenCVのRubyMotion向けラッパーはMotionCVという名前でhttps://github.com/iwazer/opencvmotioncvブランチで開発していますので、興味のある方はチェックしてみてください。

利用するサンプルプログラムもGitHubに上げてあります。

まだ、これに毛が生えただけの状態ですが...