Search code examples
swiftinitializer

Swift initializer for public class


When creating a public class, is it necessary to make the designated initializer public?

What's the difference between making it public vs not?

e.g.

public class A {
  init() {}
}

or

public class A {
  public init() {}
}

Solution

  • No

    You do not need to make it public. In fact, you can make it private. The only thing special about a designated initializer (and your classes are allowed more than one) is that they are responsible for ensuring the object is fully initialized.

    A convenience initializer (an initializer is either designated or convenience) (marked by the convenience keyword) does not have this responsibility. A convenience initializer delegates to a designated initializer first, and then after that returns, it is given the opportunity to overwrite some of the initial values. Importantly, the convenience initializer must always "delegate across". It must always call another initializer within the class.

    By contrast, a designated initializer (any initializer not marked with the convenience keyword) must take responsibility for making sure every property in the class gets a valid initial value, then it must "delegate up" (call a super class initializer, if there is a super class), then it can overwrite values if it wants.

    But nothing prevents you from create a class with nothing but private designated initializers (nothing at all).

    Even when we are inheriting from a class with a required initializer, our subclass can simply implement that initializer as a convenience initializer.

    class ParentClass {
        let foo: Int
        
        required init(foo: Int) {
            self.foo = foo
        }
    }
    
    class ChildClass: ParentClass {
        let bar: Int
        
        private init(foo: Int, bar: Int) {
            self.bar = bar
            super.init(foo: foo)
        }
        
        required convenience init(foo: Int) {
            self.init(foo: foo, bar: foo)
        }
    }
    

    The above is perfectly valid Swift.

    ChildClass has a private designated initializer. It has inherited from a parent class with a required initializer, but it has implemented that initializer as a convenience initializer. (Moreover, in contrast to your conjecture in a comment here and a question else where, the required initializer doesn't actually have to be public necessarily... context matters, and perhaps I will expand on that in an answer to your other question.)


    Moreover, in direct contrast to subjective_c's answer, you don't have to make parts of your Swift code public in order to use that code from Objective-C, and the passage from Apple he has quoted in his answer actually indicates that. You only need to mark public the things you want to be available outside of the framework in which your code has been implemented. You can put Objective-C & Swift code within the same application and the Objective-C code can see anything marked as public or internal.