Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Xcodeで値を表示する

1,240 views

Published on

「iOS 11 Programming」刊行記念 Night
Xcodeで値を表示することについて調べてみた

Published in: Software
  • Be the first to comment

Xcodeで値を表示する

  1. 1. Xcodeで値を表示する 「iOS 11 Programming」刊行記念 Night
  2. 2. 自己紹介 ● 荒巻 賢一 ● 趣味 ○ ピアノ、テニス、競技プログラミング、ボルダリング ● ライフワーク ○ デバッグ
  3. 3. Agenda ● Xcodeで値を表示することについて調べてみた
  4. 4. ある日の不具合 ● safeAreaInsetsが反映されない ○ UIScrollViewのsubviewにSafeAreaInsetが反映されないこ とがある
  5. 5. View Hierarchyで見る ● あるviewまではsafeAreaInsetsが 正しく、subviewで正しくない
  6. 6. View Hierarchyで見る Viewを右クリックし、Print Descriptionで idがわかる Printing description of $12: <UIView: 0x7fde56eaad00; frame = (0 0; 812 375); autoresize = W+H; layer = <CALayer: 0x60000043a3e0>>
  7. 7. デバッグコンソールで調べる ● デバッガからexpressionコマンド (短縮形: pまたはpo)で確認して みる
  8. 8. idからsafeAreaInsetsを調べる エラー (lldb) p [0x7fde56eaad00 safeAreaInsets] error: warning: receiver type 'long' is not 'id' or interface pointer, consider casting it to 'id' error: no known method '-safeAreaInsets'; cast the message send to the method's return type
  9. 9. idからsafeAreaInsetsを調べる idでキャストしろと言われたのでやってみる (lldb) p [(id)0x7fde56eaad00 safeAreaInsets] error: no known method '-safeAreaInsets'; cast the message send to the method's return type
  10. 10. idからsafeAreaInsetsを調べる UIViewにキャストしてみる (lldb) p [(UIView*)0x7fde56eaad00 safeAreaInsets] (UIEdgeInsets) $13 = (top = 32, left = 0, bottom = 21, right = 0)
  11. 11. idからsafeAreaInsetsを調べる しかしsuperviewでは正常に出力されない (lldb) p [[(UIView*)0x7fd688f0e670 superview] safeAreaInsets] (UIEdgeInsets _Nullable) $14 = {}
  12. 12. idからsafeAreaInsetsを調べる 戻り値をキャストすればよかった (lldb) p (UIEdgeInsets)[0x7fde56eaad00 safeAreaInsets] (UIEdgeInsets) $15 = (top = 32, left = 0, bottom = 21, right = 0) (lldb) p (UIEdgeInsets)[[0x7fde56eaad00 superview] safeAreaInsets] (UIEdgeInsets) $16 = (top = 32, left = 44, bottom = 21, right = 44) 戻り値の型がid以外のときはキャストが必要
  13. 13. 疑問 ● なぜこのような違いが生まれるのか? ● expressionコマンドは何をしているのか?
  14. 14. LLDBをビルドしてみる ● XcodeのデバッガはLLDB ○ https://lldb.llvm.org/ ● デバッガをステップ実行させれば挙動がわかるので は? ※ XcodeのLLDBとは一部異なる可能性があります
  15. 15. LLDB上でLLDBを実行する ● LLDB in LLDB LLDB in LLDB(黒) XcodeのLLDB(青)
  16. 16. ブレークポイントを設定する ● Expressionコマンドに関係しそうな場所にブレーク ポイントを設定してステップ実行してみる ○ UserExpression::Evaluate
  17. 17. expressionコマンドの式の処理 1. 式をコンパイルする 2. メッセージを組み立てる 3. オブジェクトにメッセージを送る 4. 結果を表示する
  18. 18. 式をコンパイルする ● パースして構文木(Clang AST)を得る ○ ClangExpressionParser::Parse ● 文法エラーや、存在しないセレクタを指定した場合 はここでエラーになる
  19. 19. メッセージを組み立てる (インラインアセンブラ) 1. オブジェクトのクラスを取得する 2. respondsToSelector:でYESを返すかどうか調べる 3. メッセージを送る AppleObjCRuntimeV2::CreateObjectChecker
  20. 20. 戻り値のための領域を準備する ● 呼び出し規約により場合わけ ○ ObjcObjectChecker::InstrumentInstruction ○ idのとき eMsgSend_fpret ○ 構造体のとき eMsgSend_stret ■ safeAreaInsetsはこっち
  21. 21. オブジェクトにメッセージを送る ● ターゲットプログラム上に新しいスレッドを作って オブジェクトにメッセージを送る ○ UserExpression::Execute
  22. 22. 結果を表示する ● ValueObject::Dump ● CommandInterpreter::PrintCommandOutput
  23. 23. 余談: 実行できるがデバッガで表示できない ● respondsToSelector: にNOを返すと表示できない ○ 例えばNSProxyを継承してrespondsToSelector: が未実装のとき
  24. 24. デバッグオプション (--debug or -g) メッセージ送信のコードが見られる (lldb) expression --debug -- [view safeAreaInsets] Execution was halted at the first instruction of the expression function because "debug" was requested. Use "thread return -x" to return to the state before expression evaluation.
  25. 25. まとめ ● 値を表示するときにも動的にコンパイルと実行が行 われている ● safeAreaInsetsの表示にキャストが必要なのは、呼 び出し規約の違いに起因している
  26. 26. ● iOS Engineer ● Android Engineer ● Web, Front-end & Back-end ● Site Reliability ● Ad Services ● Machine Learning ● and more…! https://smartnews.workable.com We’re Hiring!We’re Hiring!

×