Boon
Boon

Reputation: 41470

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() {}
}

Upvotes: 3

Views: 2069

Answers (2)

subjective_c
subjective_c

Reputation: 302

You don't need to make it public unless you are making it available as a framework for usage in Objective-C as well.

See: https://developer.apple.com/swift/blog/?id=5

When mixing Objective-C and Swift, because the generated header for a framework is part of the framework’s public Objective-C interface, only declarations marked public appear in the generated header for a Swift framework.

Upvotes: 1

nhgrif
nhgrif

Reputation: 62052

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.

Upvotes: 3

Related Questions