Objective-CでSwift用のStatic Propertyを定義するには?

注意: この記事は1年以上前に掲載されたものです。情報が古い場合がありますのでお気を付け下さい。

SwiftではSingletonインスタンスをstaticプロパティーとして定義することができるが、Objective-Cではそれを行うことはできない。しかしながら、Swift、特にSwift 3との整合性を図るために、Swiftから呼び出す場合に限って、Singletonインスタンスをプロパティーとして呼び出せるようにすることはできる。

まず、SwiftではSingletonインスタンスを定義するとき、以下のような定義の仕方が可能である。

class Singleton {
    static let shared = Singleton()
}

一方で、Objective-Cでは、通常は以下のような定義の仕方しかできない。

@interface Singleton
+ (instancetype)sharedInstance;
@end

従って、上記の場合、Swiftではメソッドとして扱われるようになってしまう。Swift 3では以下のように認識される。

class Singleton {
    open class func shared() -> Singleton
}

上記は、Swift 2.xまでは統一性があったため問題なかったが、iOSのSwift 3のUIKitでは軒並みプロパティーになっているため、統一性を図ることができない。

従って、@propertyの属性部分にclassを付与すれば、Swiftからはプロパティーとして扱われるようになる。

@interface Singleton
@property (class, nonatomic, nonnull, readonly) Singleton *sharedInstance;
@end

こうした場合、Swift 3からは以下のように認識されるようになる。

class Singleton {
    open class var shared: Singleton { get }
}

なお、Objective-CからはStatic Propertyとしては扱うことができないため、あくまでSwiftでの認識のためのみに使われるという状態である。これは不都合なことではあるが、そもそもObjective-CではSingletonインスタンスについてはクラスメソッドを使って呼び出すのが標準となっているため、それほど問題ないことではある。

なお、上記の場合、Xcode 7までとの互換性を考慮すると、以下のように#ifdefで分けたほうが良さそうである。例えば、以下のようにすることで、Xcode 7までと8以降で問題なくビルドが通るようになる。

@interface Singleton
#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, nonnull, nonatomic, readonly) Singleton *sharedInstance;
#else
+ (instancetype)sharedInstance;
#endif
@end

この場合、Swiftから使った場合は、Xcode 7から8にした際に修正が必要にはなるが・・・。

タイトルとURLをコピーしました