[iOSアプリ開発] 値の型を文字列で取得してみる

2 min読了の目安(約2400字TECH技術記事

こんにちは。
ZennではiOSアプリ開発の普段自分が使っているちょっとしたTipsなどを書いていければと思っております。

今回は短めに 「値の型を文字列で取得する」 をやってみたいと思います。

この方法は開発していて軽くデバッグしたいときに、お手軽に変数の値の型を調べたい時に使う方法です。

Swiftはモダン言語なのですから型を見失うようなケースは少ないですが、たまに見失うケースもあるかもしれません。歴史的に[String : Any]のような型を特定しにくい辞書型で提供されているAPIなどでは有りうるかもですね。

それでも色々と解決策はありそうですが、パッと辞書のとあるキーの値は何の型が入っているのだろうと確認するために、ちょっとした extension を作っておきました。

値の型を文字列で取得するメソッド

文字列の拡張で2つのメソッドを用意しています。クラスメソッド版とイニシャライザ版になります。どちらか片方でもいいと思いますし、共存させてもいいかなと思います。ご自由に選択してください。

import Foundation

extension String {
    
    static func typeOf(_ target: Any?) -> String {
        if let target = target {
            return String(describing: type(of: target))
        }
        return "nil"
    }
    
    init(typeOf target: Any?) {
        if let target = target {
            self.init(describing: type(of: target))
            return
        }
        self.init("nil")
    }
}

値の型の名前を文字列で取得するためには String(describing: type(of: target)) を使用することで実現できるわけですが、もし、渡された値がオプショナル型だった場合は "Optional<Any>"という文字列で固定されてしまいます。それを吸収するために、if let文で分岐をさせているのがミソになります。

使ってみる

色々と試してみましょう。

基本動作

String.typeOf("Hello") // クラスメソッド版
String(typeOf: "Hello") // イニシャライザ版

// どちらも "String" が返る

オプショナル型の時(nilのときの動作)

let url1 = URL(string: "dummy") // 生成時にnilになる
String.typeOf(url1)
// "nil" が返る

let url2 = URL(string: "https://www.yahoo.co.jp/")
String.typeOf(url2)
// "URL" が返る

辞書や配列の場合

String.typeOf([String : Int]())
// "Dictionary<String, Int>"が返る

String.typeOf(["", "", ""])
// "Array<String>"が返る

例えば辞書の場合 "[String : Int]"という文字列が返るわけではないです。

Rangeの場合

String.typeOf(1..<4)
String.typeOf(1...4)
String.typeOf(1...)
String.typeOf(..<4)
String.typeOf(...4)

// "Range<Int>"が返る
// "ClosedRange<Int>"が返る
// "PartialRangeFrom<Int>"が返る
// "PartialRangeUpTo<Int>"が返る
// "PartialRangeThrough<Int>"が返る

演算子で気軽に作れるRangeですが、それぞれに名前が付いています。

その他

全部を試すのは大変なので、ぱっと思いついたオマケを

String.typeOf(UIView.AnimationCurve.easeIn)
// "UIViewAnimationCurve"が返る
String.typeOf(FileManager.default)
// "NSFileManager"が返る

このようにSwiftでの記述と返される値には違いが生じます。

class Hoge {
    enum Fuga {
        case fuga1, fuga2
    }
}

String.typeOf(Hoge.Fuga.fuga1)
// "Fuga"が返る

カスタムなクラスに入れ子になったクラスや構造体や列挙型は、その名前だけが返るようですね(Hoge.Fugaではなく)

まとめ

というわけで簡易的に値の型を文字列で取得する方法を書いてみました。

あくまで「簡易的にパッと確認したい」ときに使用するようにしてくださいませ。
ここで返ってきた値をもってプロダクトコードの分岐条件などにしてしまうと、思わぬバグを生み出す可能性があります。

用法用量をお守りください

ではまた。