Swift: Get current class from a static method
Asked Answered
C

4

6

In Swift, let's say I want to add a static factory method that returns an instance:

class MyClass {
  static func getInstance() {
    return MyClass(someProperty);
  }
}

But what if I don't want to write the class name? Is there an equivalent of self but for static methods and properties?

Same idea if I want to call another static method from a static method:

class MyClass {
  static func prepare(){
    //Something
  }

  static func doIt() {
    MyClass.prepare();
  }
}

Can I do this without using MyClass explicitly?

Cappuccino answered 3/2, 2016 at 11:32 Comment(0)
B
4

self works in static methods too, like this:

class MyClass {
  static func prepare(){
    print("Hello");
  }

  static func doIt() {
    self.prepare();
  }
}
Bunch answered 3/2, 2016 at 11:41 Comment(4)
Thanks. What about self()? I get some errors saying I need self.init, and when I do I get some other error that I need a required initializer...Cappuccino
self() is not possible, but I'm wondering why do you want to do that? dfri describes the best practice above to create Factory design pattern. Here's another sample: github.com/ochococo/Design-Patterns-In-Swift/blob/master/source/…Bunch
The only reason I'm doing this is because the code will be copy pasted and distributed for other people to use. I thought the least things hard-coded the better... Thanks!Cappuccino
Then I recommend to use a base protocol and swift generics (details in post)Bunch
F
0

As RobberR writes above, you could just use self for accessing static function of self, and self.init(...) for your factory example. Note that you still must specify MyClass as return type in your factory method.

As an alternative, more generic approach, you could let your class conform to a factory protocol which contains a default implementation for the factory method. With this, the static factory method isn't tied to any specific class, but can however be accessed by any class conforming to the factory protocol (and an additional help protocol for common initializers).

Factory setup:

protocol FactoryInitializers {
    var commonProperty : Int { get set }
    init(commonProperty: Int)
}

protocol FactoryMethods {
    typealias T: FactoryInitializers
    static var defaultStaticCommonProperty : Int { get }
}
extension FactoryMethods {
    static func getInstance() -> T {
        return T(commonProperty: defaultStaticCommonProperty)
    }
    static func getInstanceFor(commonProperty commonProperty: Int) -> T {
        return T(commonProperty: commonProperty)
    }
}

protocol Factory : FactoryMethods, FactoryInitializers { }

Example class conformances:

class MyClass : Factory {
    typealias T = MyClass
    static var defaultStaticCommonProperty : Int = 1

    var commonProperty : Int = 0

    required init(commonProperty: Int) {
        self.commonProperty = commonProperty
    }
}

class MyOtherClass : Factory {
    typealias T = MyOtherClass
    static var defaultStaticCommonProperty : Int = 10

    var commonProperty : Int = 0

    required init(commonProperty: Int) {
        self.commonProperty = commonProperty
    }
}

Example usage:

var foo = MyClass.getInstance()
print(foo.dynamicType)    // "MyClass"
print(foo.commonProperty) // 1
foo = MyClass.getInstanceFor(commonProperty: 5)
print(foo.commonProperty) // 5

var bar = MyOtherClass.getInstance()
print(bar.dynamicType)    // "MyOtherClass"
print(bar.commonProperty) // 10
Festination answered 3/2, 2016 at 11:52 Comment(0)
B
0

You can define a Protocol and use the swift generics like this:

protocol Vehicle {
  init()
}

class MyVehicleFactory<T:Vehicle> {
  static func getInstance() -> T {
    return T()
  }
}

And the people who copied your code can do this:

class Car : Vehicle {
  required init() { }
}
let car = MyVehicleFactory<Car>.getInstance();
Bunch answered 3/2, 2016 at 17:47 Comment(0)
W
0

You can create a factory method that doesn't reference the class, like this:

class MyClass {
    static func factory() -> Self {
        let instance = Self.init()
        // other init here
        return instance
    }
}
Wayne answered 26/6, 2023 at 4:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.