Swift reuse overloaded initializers of a UIHostingController?

31 Views Asked by At

I have a UIHostingController with two very similar initializers, just with different parameters. Here is a simplified example of what I'm trying to do:

public class ExampleViewController: UIHostingController<ExampleView> {
  public let var1: Int
  public let var2: String

  public init(var1: Int, var2: String) {
    self.var1 = var1
    self.var2 = var2
    super.init(rootView: ExampleView(var1, var2))

  }

  public convenience init(var1: Int) {
    self.var1 = var1
    self.var2 = “”
    super.init(rootView: ExampleView(var1, ""))
  }
}

Since my real use case is more complicated than this example, it would be great if I could reuse the shared logic in the initializers, something like this:

public class ExampleViewController: UIHostingController<ExampleView> {
  public let var1: Int
  public let var2: String

  public init(var1: Int, var2: String) {
    self.var1 = var1
    self.var2 = var2
    super.init(rootView: ExampleView(var1, var2))
  }

  public init(var1: Int) {
    self.init(var1: var1, var2: "")
  }
}

However, I am unable to reference self/self.init until all properties are set and super.init is called. Does this mean that I’m not able to reuse the initializer logic, or is there another way of doing this?

1

There are 1 best solutions below

3
Alexander On

Your intuition is correct; deduplicating initialization logic is a good idea.

For it to work correctly, you need to mark you second initializer with convenience:

// ...
  public convenience init(var1: Int) {
    self.init(var1: var1, var2: “”)
  }

Usually these are the most clear when most initializers are just a customization/specialization implemented in terms of some other centralized initializer. A picture is worth a thousand words:

Swift designated initializer call hierarchy

Ideally, you only have 1 designated initializer at each level, where possible.


However, in this case, you can just leverage Swift's ability to have default parameter values, and get away with just a single simple initializer:

public class ExampleViewController: UIHostingController<ExampleView> {
  public let var1: Int
  public let var2: String

  public init(var1: Int, var2: String = "") {
    super.init(rootView: ExampleView(var1, var2))
    self.var1 = var1
    self.var2 = var2
  }
}

This is likely just a toy example, but I'll caution anyway: "" is almost never an appropriate default value for strings (contrary to the defaults baked into other languages, like 0 values in Go or default-initialized values in Java).