15
14

More than 5 years have passed since last update.

[Swift] Arrayの中身をLLDBで確認する(map関数で)

Posted at

タイトルでピンときた方は、たぶんそれ以上の事は書かれていませんので読まなくても大丈夫かと思います。

結論

po array.map { "\($0.name)" }

という感じで、map関数で各要素を文字列に変換すると楽です。

事前知識(とstructclassの挙動の違い)

以下のようなコードがあったとします。

struct Dog {
    let name: String
    let age: Int
    let type: String
}
let array: [Dog] = [
    Dog(name: "ポチ", age: 3, type: "柴犬"),
    Dog(name: "ジョン", age: 4, type: "ゴールデンレトリバー"),
    Dog(name: "エレナ", age: 2, type: "プードル"),
]
print(array) // ここでbreak!

上記をpo arrayすると以下のように出力されます。
Kobito.HDvbw3.png

まぁ悪くはありません。

ちなみにDogCustomDebugStringConvertibleに準拠していないにも関わらず、このように中身が(箇条書きで)出力されるのはstructで宣言している為です。

これがclassで宣言した場合は、以下のとおりです。

(lldb) po array
▿ 3 elements
  ▿ [0] : <(Dog #1): 0x7fcd7240fa40>
  ▿ [1] : <(Dog #1): 0x7fcd7240fa90>
  ▿ [2] : <(Dog #1): 0x7fcd7240fae0>

CustomDebugStringConvertibleに準拠すれば以下のように実装した文字列で出力されます。

class Dog : CustomDebugStringConvertible {
    ...
    var debugDescription: String {
        return "\(name): \(age)"}
    }
}
(lldb) po array
▿ 3 elements
  ▿ [0] : ポチ: 3
  ▿ [1] : ジョン: 4
  ▿ [2] : エレナ: 2

ちなみにstructで準拠した場合は、前述の出力に 加えて debugDescriptionの内容が出力されます。

(lldb) po array
▿ 3 elements
  ▿ [0] : ポチ: 3 ★ここの出力が追加されてる★
    - name : "ポチ"
    - age : 3
    - type : "柴犬"
  ▿ [1] : ジョン: 4
    - name : "ジョン"
    - age : 4
    - type : "ゴールデンレトリバー"
  ▿ [2] : エレナ: 2
    - name : "エレナ"
    - age : 2
    - type : "プードル"

このようにclassstructで少し挙動は違いますが、CustomDebugStringConvertibleに準拠すれば、任意の文字列でArrayの中身を出力することが出来ます。

いつ(map関数を)利用するか?

さて、(多くの記事で書かれていることですが)CustomDebugStringConvertibleに準拠すれば(というよりもdebugDescriptionを実装すれば)、独自の型でも自由な文字列で出力できることが分かりました。

そうするとタイトルと冒頭で書いたような、map関数を利用するモチベーションは無いように感じるかもしれません。

ただし、debugDescriptionによるデバッグの場合、以下の点が不便に感じます。

  • 出力内容を変えたい場合にコードを変更して再ビルドが必要になる。
  • structの場合、箇条書きで出力されてしまうので要素数が多い場合にやたら長くなる。

そこでLLDBでpoする時にmap関数を利用して、その場で必要な文字列を組み立てるようにすれば、再ビルドは不要で、その場で必要な情報だけを出力できるようになります。

種類と名前だけを列挙する
(lldb) po array.map{ "[\($0.type)] \($0.name)" }
 3 elements
  - [0] : "[柴犬] ポチ"
  - [1] : "[ゴールデンレトリバー] ジョン"
  - [2] : "[プードル] エレナ"
structでdebugDescriptionの内容だけを出力する
(lldb) po array.map{ String($0) }
 3 elements
  - [0] : "ポチ: 3"
  - [1] : "ジョン: 4" { ... }
  - [2] : "エレナ: 2"

これはビルド時間がかかる巨大なプロジェクト、structで多数のプロパティが定義されている場合などに特に有効かと思います。

まとめ

CustomDebugStringConvertibleに準拠、すなわちdebugDescriptionを実装するテクニックは開発時のほとんど多くの場面で有効です。一度実装してしまえば、 あなた以外もこの恩恵を受けることができる というのは重要な点です。

一方で、 デバッグ時に必要な情報は時と場合によって異なる という事実もあります。あるケースでは有効なデバッグ出力について別のケースではノイズにもなりえますし、その逆も然りです。

そうした場合にmap関数を利用して、 その場で必要なデバッグ情報を出力する というアイディアが活用できることもあるのでは無いでしょうか?

P.S.

以下の記事を読ませていただいて、(重複する部分があるとは思いつつも)自分なりのデバッグ手法も書いてみました。

初級者から中級者にレベルアップするためのXcodeデバッグ術
http://himaratsu.hatenablog.com/entry/xcodedebug

15
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14