This is a relatively common design pattern:
https://stackoverflow.com/a/17015041/743957
It allows you to return a subclass from your init
calls.
We can take advantage of a compiler quirk - self
is allowed to be assigned in protocol extensions - https://forums.swift.org/t/assigning-to-self-in-protocol-extensions/4942.
Thus, we can have in place something like this:
/// The sole purpose of this protocol is to allow reassigning `self`
fileprivate protocol ClusterClassProtocol { }
extension ClusterClassProtocol {
init(reassigningSelfTo other: Self) {
self = other
}
}
/// This is the base class, the one that gets circulated in the public space
class ClusterClass: ClusterClassProtocol {
convenience init(_ intVal: Int) {
self.init(reassigningSelfTo: IntChild(intVal))
}
convenience init(_ stringVal: String) {
self.init(reassigningSelfTo: StringChild(stringVal))
}
}
/// Some private subclass part of the same cluster
fileprivate class IntChild: ClusterClass {
init(_ intVal: Int) { }
}
/// Another private subclass, part of the same cluster
fileprivate class StringChild: ClusterClass {
init(_ stringVal: String) { }
}
Now, let's give this a try:
print(ClusterClass(10)) // IntChild
print(ClusterClass("abc")) // StringChild
This works the same as in Objective-C, where some classes (e.g. NSString
, NSArray
, NSDictionary
) return different subclasses based on the values given at initialization time.