タイトルでピンときた方は、たぶんそれ以上の事は書かれていませんので読まなくても大丈夫かと思います。
結論
po array.map { "\($0.name)" }
という感じで、map
関数で各要素を文字列に変換すると楽です。
事前知識(とstruct
とclass
の挙動の違い)
以下のようなコードがあったとします。
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!
まぁ悪くはありません。
ちなみにDog
がCustomDebugStringConvertible
に準拠していないにも関わらず、このように中身が(箇条書きで)出力されるのは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 : "プードル"
このようにclass
とstruct
で少し挙動は違いますが、CustomDebugStringConvertible
に準拠すれば、任意の文字列でArrayの中身を出力することが出来ます。
いつ(map関数を)利用するか?
さて、(多くの記事で書かれていることですが)CustomDebugStringConvertible
に準拠すれば(というよりもdebugDescription
を実装すれば)、独自の型でも自由な文字列で出力できることが分かりました。
そうするとタイトルと冒頭で書いたような、map関数を利用するモチベーションは無いように感じるかもしれません。
ただし、debugDescription
によるデバッグの場合、以下の点が不便に感じます。
- 出力内容を変えたい場合にコードを変更して再ビルドが必要になる。
-
struct
の場合、箇条書きで出力されてしまうので要素数が多い場合にやたら長くなる。
そこでLLDBでpoする時にmap関数を利用して、その場で必要な文字列を組み立てるようにすれば、再ビルドは不要で、その場で必要な情報だけを出力できるようになります。
(lldb) po array.map{ "[\($0.type)] \($0.name)" }
▿ 3 elements
- [0] : "[柴犬] ポチ"
- [1] : "[ゴールデンレトリバー] ジョン"
- [2] : "[プードル] エレナ"
(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