2017年5月24日水曜日

Xcode 8.3 & Swift 3.1 環境で LLDB を使う Tips

以前も似たような記事書いた気がするんですが、定期的にSwiftのコード上でLLDBを使ってて困ることがあるので定期的に書くことにします。ほとんど https://stackoverflow.com/questions/29441418/lldb-swift-casting-raw-address-into-usable-type からの転載です。

LLDBの言語を指定して実行する

標準ではbreakpointを挟んでbreakした行がSwiftであればSwift、Objective-CであればObjective-CでLLDBの言語が選択されるようなのですが、これでは毎回毎回breakした地点に応じてデバッグの仕方が変わって大変で仕方がないので、Swiftに統一してしまうのが良いと思っています。
expr -l swift -- {Swift Command}
e -l swift -- {Swift Command}
とすると常にSwiftでLLDBに対してコマンドを送る事が可能になります。逆にObjective-C側に寄せたい場合は
expr -l objc++ -O -- {Objective-C Command}
e -l objc++ -O -- {Objective-C Command}
とすれば良いです。-Oオプションがないと結果がいい感じにObjective-Cのオブジェクトとして扱われないので注意。

importを忘れずに

以前も書いた気がしますがLLDBでbreakした環境はそのままだとFoundation.frameworkすらまともに使えない(シンボルを認識しない)状態なので、importを忘れずにしましょう。
e -l swift -- import UIKit
e -l swift -- import MyApp
e -l swift -- import MyAppLib
という具合でしょうか。他必要なものがあればその都度。注意点として自分のアプリ自体に含まれるシンボル、例えばAppDelegateだとかViewControllerのたぐいだとかもimportしないと触れないので忘れないように。

unsafeBitCast(_:to:)を使ってポインタからオブジェクトを取得する

これも以前書いた気がしますが、Swift 3でまたシグネチャが変わったらしいので念のため。
e -l swift -- let $obj = unsafeBitCast(0x00000000, to: MyClass.self)
e -l swift -- print($obj)
とかやるといい具合になります。

エイリアスを作ろう

毎回e -l swift -- とかタイプするの面倒ですし、poがe -O -- のエイリアスなのと同様に、eswiftとかpswiftとかそういうエイリアスを作ってしまえばいいと思います。~/.lldbinitの中に、
command alias eswift e -l swift -- 
とか書いておけば良い気がします。

2017年3月7日火曜日

NSAttributedString に lineSpace を付与したとき、1行であるにも関わらず lineSpace が下端に付与されて困っている人はこれを読んだら直ります



突然ですが皆さん、NSAttributedStringには2017/03/07付のiOS 10.3現在でも致命的にバグっている箇所があります。

症状:

  • NSAttributedStringにNSParagraphStyleAttributeNameを利用してNSParagraphStyle経由でlineSpaceが付与されている。
  • NSAttributedStringに複数の「区間」が存在する。例えばNSAttributedString全体が単一のAttributeによって構成されているときはこの問題は発生しません。2つ以上の異なるAttributeの区間が必要です。
  • NSAttributedStringを描画するときに、横幅及び文字列の長さの都合で、1行で描画される。複数行になるときにはこの問題は発生しません。
  • NSAttributedStringにNSBackgroundColorAttributeNameが付与されていない。または、NSBackgroundColorAttributeNameとNSKerningAttributeNameの両方が付与されている。

上記の条件を全て満たすとき、
本来、1行の文字列はレンダリングしたときに下端にlineSpaceが付与されてはいけませんが、この条件が満たされていると下端にlineSpaceが付与されてしまいます。先頭の画像の左上のケースがこの問題に相当します。

具体的な問題としては、
  • 問題が発生するNSAttributedStringを使用したUILabel, UITextField, UITextViewの描画内容が思いっきり上にずれます(下に無駄なスペースが発生するので)
  • NSAttributedStringの地点で壊れているので、Core Textを利用したり、boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRectを使っても一切回避できません

解決策: 

この問題に対する正しいワークアラウンドの方法は一つしかありません。

NSAttributedStringの全Attribute区間にNSBackgroundColorAttributeNameを付与し、かつどの区間にもNSKerningAttributeNameを付与しない。

背景色が不要の場合はUIColor.clearでも付与してごまかしてください。
以上です。よろしくお願いします。

参考:

2016年12月13日火曜日

Instruments を使っていてシンボルが見えないときの対処法

Instruments を久しぶりに起動して Time Profiler を使おうとしたら、びっくり仰天シンボルが全部見えない状態になっているじゃあありませんか。 Swift化したのがあかんのか!?と思って調べてみました。

結論から言うと、先日ビルドの軽量化のためにDebugビルド時にdSYMの出力を止めていたのが原因でした(´・_・`)
http://stackoverflow.com/questions/36882788/how-to-create-dsym-file-in-xcode-7-0
Debug Information FormatをDWARF with dSYM Fileに戻して、dSYMの出力を再開したら問題なくシンボルが出力されるようになりました。なんじゃそりゃ。

それでもだめな場合はInstruments側のFile -> Symbols... を選択すると、直接モジュールのdSYMを指定する事が可能になります。覚えておくと便利かもです。
http://stackoverflow.com/questions/33683690/apple-instruments-has-mangled-symbols-and-greyed-out-symbol-names-when-profiling