ラベル Xcode 5.0 の投稿を表示しています。 すべての投稿を表示
ラベル Xcode 5.0 の投稿を表示しています。 すべての投稿を表示

2014年1月7日火曜日

LLDB のカスタムコマンドを Python で書いてみようとして大失敗した話

なんかうまくいかないんです(´・_・`)

Xcode 5のデバッガとして用意されているLLDBですが、実は設定ファイルを書くことで自由にカスタマイズすることが可能になっています。またPythonを使ってより深いLLDB自体の挙動をカスタマイズすることも出来るらしいと最近教えてもらいました。

参考: http://qiita.com/dealforest/items/e3a5284badd17733ccc1

さてこちらの参考記事に、
例えば動的に生成した UIImage をファイルに出力するコマンドとかは便利そうですね。
というなかなか夢のある発言があるのですが、残念ながらこちらの記事の中では実際のコードがありません。ということでLLDBの設定の練習がてら、私の方で早速デバッガからUIImageをファイルに書き出すコマンドの作成にチャレンジしてみました。

■実装方針

LLDBを操作するために使用できるPythonモジュールについては、LLDBの公式ページに詳しいドキュメントが揃っています。
http://lldb.llvm.org/python-reference.html (簡単な解説とチュートリアル)
http://lldb.llvm.org/python_reference/ (APIドキュメント)

また既に何人かの方が似たようなことをされた形跡があります。
http://stackoverflow.com/questions/12668815/lldb-python-access-of-ios-variables
http://stackoverflow.com/questions/18468126/pointer-arithmetic-in-lldb-python-scripts
http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000321.html

これを元にして、以下の様な戦略でいってみます。

  1. 引数のUIImageをUIImagePNGRepresentation関数を通してNSDataにする。
    • ただのUIImageをそのままファイルに書き出しても使えませんので、まず一旦JPEGなりPNGなりに変換する必要があります。ここではObjective-C側に変換してもらうことにします。
  2. NSData bytesを取得する。
    • expr (const void *)[(NSData *)UIImagePNGRepresentation(image) bytes]とか叩けば一発なはずなので、その方針で行きます。
  3. ファイルに書き出す。
    • exprの結果をraw dataで取り出せれば、あとは普通にファイルに書き出しておしまいです。簡単そうですね。
ということで出来たコードはこちら。


■しかし

やはりというか落とし穴がorz
冒頭の画像にもあるのですが、Python経由でexprした実行結果を取得する手段がどうにも見つかりません。SBFrame.EvaluateExpression(expr)の結果がSBValueなんだからそっからデータが引けるだろうと思っていたのですが、何を実行しても壊れたSBValueしか返却されないためどうにもうまくいきません。SBDebuggerやSBCommandInterpreter経由でHandleCommand(expr, result)する手も考えたのですが、今度はresultから値を取る手段がない(resultをコンソールではなくファイルにリダイレクトする手段しか無い)ためやはり断念です・・・

うーん。もう少し頑張ったらうまくいきそうな気もするのですが。残念です><


2014年1月6日月曜日

Spark Inspectorを一ヶ月ほど使ってみた感想


ちょっと仕事で複雑なiOSの画面を作りたいということになり、デバッグに難儀していた所、Spark InspectorというiOS向けのランタイムインスペクタツールが発売されていましたので、やや乗り遅れた感がありますが私も早速試してみました。

Spark Inspectorを使うと、

  • リアルタイムにViewの構造を視覚的に確認し、直接プロパティの値を編集してアプリに反映させることができる
    • Webエンジニアの人にわかりやすくたとえるならば、ChromeやFirefoxなどに付いているインスペクタをiOS上で使えるようなものです
  • その他、アプリ内を飛び交っているNSNotificationの状態を監視することができる(らしい)

既に試された方のブログ記事で導入方法など詳しく公開されていますので、まずはそちらを見ていただくのが良いかと思います。
Spark Inspectorを導入してみた
http://inon29.hateblo.jp/entry/2013/12/06/002948
[Xcode][tool] ランタイムデバッガーSpark Inspectorが便利!
http://blog.natsuapps.com/2013/05/spark-inspector.html
ということで、私は一ヶ月ほど実際に仕事で使ってみて良かった点と悪かった点をまとめてみようかと思います。興味ある方の参考になればと思います。

■良かった点

導入が非常に楽です。ブログ記事で既に紹介されている方法は自分のプロジェクトに必要なフレームワークを組み込んで設定する方法ですが、最近のSpark Inspectorはこの方法を用いなくてもXcodeから一発で必要なフレームワークを動的に読み込んでインスペクタを起動してくれます。

Viewの階層構造をリアルタイムに監視できるのはやはり非常に有効です。これまではUIView- (void)recursiveDescriptionプライベートメソッドを呼び出したりして状態を確認したりしていたのですが、実行中の画面に対して動的に状態を見て、動的にプロパティの値を書き換えて見た目を調整することができるのは劇的に作業効率を改善してくれます。これってWebプログラミングだと実に当たり前のことなんですが、iOSプログラミングだと余りまだ普及してない考えだなと思います。

動作はやや重いですが、2012年モデルのMacBook Airでも問題なく動作させることが出来ました。もちろんiPadのアプリでもちゃんと動作します。

■イマイチだった点

楽に導入できる、自分のプロジェクトに必要なフレームワークを組み込まないやり方では、いくつか制限があります。

  • 自分のプロジェクトに必要なフレームワークを組み込まないと、実機でSpark Inspectorを動作させることが出来ない。
  • 動作が非常に安定しない。プロジェクトによってはかなりの確率で起動に失敗したりする。今回私が仕事で使っていたプロジェクトでは8割ぐらいの確率で起動に失敗していた。

それから地味に痛いのが、表示と編集が可能なのが現状CALayerとUIViewのプロパティのみに制限されているところです。Auto Layoutには対応していませんし、例えばUIScrollViewのcontentInsetを動的に調整してみたりですとかUIButtonの横幅とタイトルを動的に調整してみたりですとかそういう小技が出来ないため、なんというかかなり中途半端感を受けます。結局私の場合は表示されているはずなのに表示されていないViewの構造を調べる程度の用途にとどまりました。

2013年12月9日月曜日

Xcode 5 で、発生した NSException の詳細が表示されない時の対処法

原因がよくわからないのですが、iOSアプリをデバッグ中にNSExceptionが発生してアプリがクラッシュしてしまった時、その詳細がXcodeのコンソール上に表示されなくなってしまいました。普通はデフォルトのexception handlerがうまい具合にやってくれるのですが、何らかの理由でそれがうまくいかない場合があるようです。自分でスレッド立ててるとかでしょうか・・・


上図のように、例外が発生している箇所にブレークポイントをおいてどこで発生したのかを知ることはできるのですが、実際には発生箇所がわかっても発生原因がさっぱりわからないというケースもあります。例えばiOSのシステムが例外を発生させたときや、コードが公開されていないライブラリが例外を発生させたときなどです。

さて、このようなときは発生しているNSExceptionのdescriptionを直接読めれば便利そうです。というわけで調べてみました。

http://stackoverflow.com/questions/384775/how-do-i-find-out-what-exception-was-thrown-in-the-xcode-debugger-for-iphone
After you stop in the debugger, you can enter po $eax (simulator) or po $r0 (device) to see the exception. This is because the exception object is passed as the first argument to objc_exception_throw, which is kept in register r0 or EAX.
こちらの投稿のコメントにちょっとだけ書かれている方法がどうやら一番良さそうです。というわけで試してみました。
  1. まずはプロジェクトのAll Exception Breakpointを有効にします。
  2. アプリをデバッグして、例外が発生する箇所を実行します。
  3. 例外発生箇所でブレークポイントが発動したら、左のスタックトレースナビゲーションから、スタックトレースの一番上(objc_exception_throw)を選択します。
  4. コンソール上で以下のコマンドを実行します。
    • シミュレータなら、po $eax
    • 実機上なら、po $r0
うまくいきました!これで万一発生した例外の原因がよくわからない場合でも安心です。

余談ですが、eaxレジスタ/r0レジスタは関数の引数だかなんだかに相当するレジスタみたいなので、よくわからないコードで詰まっている場合はここを見れば他のケースでも解決できるかもしれません。

2013年10月30日水曜日

【誰得】ncursesをiOS 7向けにビルドしてみた



久々のブログ投稿がこんな内容でほんとすみません。

ややタイトル出落ち感がありますが、ncursesをiOS向けにビルドしてみました。環境は以下のとおりです。

  • OS X 10.8.5 (Mountain Lion)
  • Xcode 5.0 & iOS SDK 7.0
  • ncurses-5.9
  • TerminalにはOS X付属のTerminal.appを使用

※注意: 本当に使えるかどうかまでは試してません。ちょっと根性が足りませんでした。あくまでiOS向けにC/C++で書かれたライブラリをビルドして使えるようにするときの参考になったりならなかったり程度でお考えください。

というわけで、まずはncursesのソースコードをhttp://ftp.gnu.org/gnu/ncurses/あたりからサクッと拾ってきます。今回はncurses-5.9を使用しましたがどのバージョンでも大して変わらないと思います。

あとはconfigureしてmakeすればOKですが、configureが少々厄介です。そのままだとerror: Cross-build requires two compilers.とか言われてしまいますので、./configureの当該箇所をコメントアウトしてからオプションを付けて実行してください。それから./configureを実行した端末エミュレータ向けにビルドされてしまうようで、その挙動を変更するオプションが見つからなかったのでこちらも注意してください。私は今回xterm向けにビルドしてしまいましたがxtermエミュレータが用意できない場合はVT100などに変更した上でビルドしたほうが良いかと思います。



うまくいけば無事ビルドが通ってタイトルの画像のようになります。
CFLAGSでarchとisysrootを指定してビルドする手法は他のautoconfを使っているオープンソースのライブラリでも応用できそうですね。

さてlibncurses.aはビルドできたのですが、このままでは端末エミュレータがなくてどうにもならないので、iOS用の端末エミュレータを用意しなければなりません。幸いにしてオープンソースのmobileterminalというプロジェクトを見つけましたので、こちらをお借りしましょう。ライセンスがGPLですがどうせこんな酔狂なものを人様の前に晒すことは決してないはずなので問題ありません。

あとはhttp://www.kis-lab.com/serikashiki/man/ncurses.htmlでも参考にncursesでのCUIプログラミングをお楽しみください。多分、きっと、運が良ければ、動くと思います。


参考文献:
http://d.hatena.ne.jp/maminus/20100129/1264781242 - configureのbuild、host、targetの違い
https://twitter.com/moriyoshit - @moriyoshi