きっかけ
ViewController名をインスタンスに依存せずに取得、また定義も一箇所にまとめられないかと考えていました。
親クラスのstatic propety
当然ながらSuperと出力される
.swift
class Super {
static var name: String {
String(describing: self)
}
}
class Sub: Super {
}
print(Super.name)
print(Sub.name)
出力
Super
Super
protocol extensionをつかって実現する
.swift
class Super: NameConvertible {
}
class Sub: Super {
}
protocol NameConvertible {
static var name: String { get }
}
extension NameConvertible {
static var name: String {
String(describing: Self.self)
}
}
print(Super.name)
print(Sub.name)
出力
Super
Sub
なぜこのような動きになるのか
ProtocolのSelfはProtocolを採用した具体的な型そのものを指すという言語仕様がキーになります。
つまりSelf.selfは
Protocolを採用した具体的な型のメタタイプを指すことから、サブクラス名が返却されます。
.swift
extension NameConvertible {
static var name: String {
String(describing: Self.self)
}
}
使い所
- UITableViewCellなどに適用し、identifierの宣言を簡略化させたいとき。
- エラーメッセージやロギング向けにクラス名をインスタンスに依存せず取得し、かつ各クラスで実装せずに済ませたいとき。
おわりに
staticなpropertyだけど継承が影響する少し不思議にも感じる動きですが、理由を理解すると便利です。
protocol extensionなので、UIKitのクラスなどに適用できるのがポイントかと思います。
とはいえ、今回のような本来静的な値をするくらいの、シンプルな利用くらいが良さそうです。