Can I have a subclass of my class as property in Swift? - swift

In Swift 2.1 I need to initialize every properties before use the class method. But if I want to have a property that is a subclass of it, I will have an infinite loop. Is this possible?
class Myclass {
let mySubClass:SubClass
init() {
mySubClass = SubClass()
print("Init my class")
}
}
class SubClass:Myclass {
override init() {
print("Init subclass")
}
}
let myClass = Myclass()

You could use a lazy stored property.
The instance of the subclass isn't initialized until it's used the first time.
class Myclass {
lazy var mySubClass : SubClass = {
return SubClass()
}()
init() {
print("Init my class")
}
}
class SubClass:Myclass {
override init() {
print("Init subclass")
}
}
let myClass = Myclass()
myClass.mySubClass

I think you're better off to be explicit about the relationships. Something like:
class Myclass {
var mySubClass:SubClass?
init() {
print("Init my class")
}
}
class SubClass:Myclass {
override init() {
print("Init subclass")
}
}
var myClass = Myclass()
let mySub = SubClass()
myClass.mySubClass = mySub

Related

Swift method chaining, how to reuse classes and methods?

Consider the following example
class ClassA {
func createAnInstanceOfAnotherClass() -> AnotherClass {
return AnotherClass()
}
func callMeA() {
}
}
class ClassB {
func createAnInstanceOfAnotherClass() -> AnotherClass {
return AnotherClass()
}
func callMeB() {
}
}
class AnotherClass {
func doSomethingAndReturn() {
return
}
}
class MethodChain {
func methodChainTest() {
ClassA()
.createAnInstanceOfAnotherClass()
.doSomethingAndReturn() //return to ClassA
.callMeA() // call classA callMe
ClassB()
.createAnInstanceOfAnotherClass()
.doSomethingAndReturn() // return to ClassB
.callMeB() // call ClassB callMe
}
}
Is it possible for the class AnotherClass to return the instance of the class that created it?
In this example I want to use the class method doSomethingAndReturn when method chaining with both ClassA and ClassB and then contione the method chain with methods from either ClassA or ClassB
You could make AnotherClass generic with a type parameter Creator, which stores the type of its creator.
class ClassA {
func createAnInstanceOfAnotherClass() -> AnotherClass<ClassA> {
return AnotherClass(creator: self)
}
func callMeA() {
}
}
class ClassB {
func createAnInstanceOfAnotherClass() -> AnotherClass<ClassB> {
return AnotherClass(creator: self)
}
func callMeB() {
}
}
class AnotherClass<Creator: AnyObject> {
// weak to avoid retain cycles!
private weak var creator: Creator?
init(creator: Creator) {
self.creator = creator
}
func doSomethingAndReturn() -> Creator {
// assuming you always do method chaining,
// and not do something weird with the intermediate results,
// this should be safe to unwrap forcefully
creator!
}
}

Why is the subclass type not available when an instance property is initialized by a static member?

When the following code is run, the self inside of defaultModuleName is ReactViewController when one would expect it to be FooViewController. Why?
class ReactViewController: UIViewController {
var moduleName: String = defaultModuleName
static var defaultModuleName: String {
let t = String(reflecting: self) // Also tried NSStringFromClass
guard let s = t.split(separator: ".").last else { return "" }
guard let r = s.range(of: "ViewController") else { return "" }
return String(s.prefix(upTo: r.lowerBound))
}
}
class FooViewController: ReactViewController {
override func viewDidLoad() {
super.viewDidLoad();
print(moduleName); // Prints "React"
}
}
This is pretty interesting; it appears that the self available in a property initialiser is merely the type that the property is defined in, rather than the dynamic type of the instance being constructed.
A more minimal example would be:
class C {
static var foo: String { return "\(self)" }
let bar = foo // the implicit 'self' in the call to 'foo' is always C.
}
class D : C {}
print(D().bar) // C
In the property initialiser for bar, the implicit self is C.self, not D.self; despite the fact that we're constructing a D instance. So that's what the call to foo sees as self.
This also prevents class member overrides from being called from property initialisers:
class C {
class var foo: String { return "C" }
let bar = foo
}
class D : C {
override class var foo: String { return "D" }
}
print(D().bar) // C
Therefore I regard this as a bug, and have filed a report here.
Until fixed, a simple solution is to use a lazy property instead, as now self is the actual instance (upon the property being accessed for the first time), which we get can get the dynamic type of with type(of: self).
For example:
class C {
static var foo: String { return "\(self)" }
// private(set) as the property was a 'let' in the previous example.
lazy private(set) var bar = type(of: self).foo
}
class D : C {}
print(D().bar) // D
Applied to your example:
class ReactViewController : UIViewController {
lazy var moduleName = type(of: self).defaultModuleName
static var defaultModuleName: String {
let t = String(reflecting: self) // Also tried NSStringFromClass
guard let s = t.split(separator: ".").last else { return "" }
guard let r = s.range(of: "ViewController") else { return "" }
return String(s.prefix(upTo: r.lowerBound))
}
}
class FooViewController : ReactViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(moduleName) // Prints "Foo"
}
}
You just need to pass self instead of type(of: self), and use the String(describing:) initializer.
class ClassA {
static var className: String {
return String(describing: self)
}
}
class ClassB: ClassA { }
print(ClassB.className) // prints "ClassB"
EDIT: clarification on the var moduleName: String = defaultModuleName update. Suppose I add this line to the above example (same idea):
class ClassA {
// This is a property of ClassA -> it gets implicitly initialized
// when ClassA does -> it uses ClassA.className for its value
var instanceClassName = className
static var className: String {
return String(describing: self)
}
}
class ClassB: ClassA { }
print(ClassB().instanceClassName) // prints "ClassA"
This new instanceClassName is not static, so it is an instance property on ClassA. It is therefore initialized when ClassA is initialized (not when ClassB is initialized). Ergo, a property being set within ClassA, using a reference to className, will print out ClassA.

Swift singleton subclass(inheritance)

I know the simplest way to write singleton in swift is
class A {
static let shared = A()
private init() { //... }
func a() {}
}
// usage
A.shared.a()
the question is that is it possible to write a subclass singleton of class A?
I got the following code from someone to do it by class function
class A {
class func shared() -> A {
private struct _A {
static let _shared = A()
}
return _A.shared
}
func a() { //... }
}
class B: A {
class func shared() -> B {
private struct _B {
static let _shared = B()
}
return _B.shared
}
func b() { //... }
}
// usage
A.shared.a()
B.shared.b()
but the problem is that I can't use private init() to hide initialization here, since there is no protected init() to do this
Does anyone know how to subclass a singleton class by using the private init()?
thanks!
I'm not sure this is a good idea to go down this road. However, if you must, you could keep them in the same file and use fileprivate to accomplish this.
in class A declaration:
fileprivate init() { }
in class B declaration:
override fileprivate init() { }
Good luck!

How to initialize variables inside subclasses' initializer that will be used in the super class's initializer?

In the following code, my intention is to have repeatNum declared in the base class because it is used in the base class (inside init and other functions). And each subclass should set repeatNum because only the subclass knows its own value.
class Base {
var repeatNum: Int
init() {
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
repeatNum = 10
super.init()
}
}
class SubClass2 : Base {
override init() {
repeatNum = 5
super.init()
}
}
Of course, it prompts some errors:
For the base class:
'self.repeatNum' not initialized
Return from initializer without initiating all stored properties.
For the subclasses:
use of 'self' in property access 'repeatNum' before super.init initializes self
I know I can simply call super.init() before setting repeatNum in the subclasses, but I really need to use repeatNum inside the base's init() in the real case. It becomes a paradox for me here somehow.
I also understand I can change the design to make the errors go away, but I am wondering if it's possible to achieve my original intention with some tweaks? I probably miss something here.
Your current code doesn't even compile, does it? It should complain about trying to use repeatNum before being initialized...
Maybe something like this could be an option for you?
class Base {
var repeatNum: Int
init(repeatNum: Int) {
self.repeatNum = repeatNum
for _ in 0..<repeatNum {
print("*")
}
}
}
class SubClass1 : Base {
init() {
super.init(repeatNum: 10)
}
}
class SubClass2 : Base {
init() {
super.init(repeatNum: 5)
}
}
i don't know what is you want,the following code is that ok
class Base {
var repeatNum: Int?
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
self.printyourneed()
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
self.printyourneed()
}
}
or
class Base {
var _repeatNum:Int?;
var repeatNum: Int?{
get{
return _repeatNum
}
set{
_repeatNum = newValue
printyourneed()
}
}
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
}
}

In Swift, is there a keyword like self but for the class?

class mySuperClass{
static var sharedInstance = mySuperClass()
var test = "hello"
}
In this little snippet, I am setting a static var to mySuperClass() to create a simple singleton.
Is there a way to do this without using the class name mySuperClass?
I ask, because I want to subclass something like this and have the subclass create a sharedInstance of itself and NOT of the super class which is what it does.
Full code here (playground-able):
import Cocoa
class mySuperClass{
static var sharedInstance = mySuperClass()
var test = "hello"
}
class mySubClass:mySuperClass{
override init() {
super.init()
test = "hello from subclass"
}
}
print(mySuperClass.sharedInstance.test)
print(mySubClass.sharedInstance.test) //prints test from mySuperClass not subClass
In other words you want to subclass a Singleton.
Let me know if this does solve your problem.
class MySuperClass {
private static let superClassInstance = MySuperClass()
class var sharedInstance: MySuperClass { return superClassInstance }
private init() { }
var test = "hello"
}
class MySubClass: MySuperClass {
private static let subClassInstance = MySubClass()
override class var sharedInstance: MySubClass { return subClassInstance }
private override init() {
super.init()
test = "hello from subclass"
}
}
print(MySuperClass.sharedInstance.test) // "hello"
print(MySubClass.sharedInstance.test) // "hello from subclass"