Search code examples
swiftobjective-cinterop

Can a Swift init be made available only for ObjectiveC?


Suppose I have a Swift class

@objcMembers class C: NSObject {
  let range: ClosedRange<Int>

  init(range: ClosedRange<Int>) {
    self.range = range
    super.init()
  }

  convenience init(min: Int, max: Int) {
    self.init(range: min...max)
  }
}

Is there a way to make the convenience init available only from Objective-C, so that the API will be smaller?


Solution

  • You can expose the method to Objective-C runtime and make it private at the same time. This however requires you to introduce the private method's interface yourself (ideally by extending the auto-generated interface, rather than introducing a separate class declaration). Your swift class should look something like this:

    @objc(TDWSwiftObject)
    class SwiftObject: NSObject {
    
        let range: ClosedRange<Int>
    
        init(range: ClosedRange<Int>) {
            self.range = range
            super.init()
        }
    
        @objc private convenience init(min: Int, max: Int) {
            self.init(range: min...max)
        }
    
    }
    

    And then add the missing Objective-C parts as a class category:

    @interface TDWSwiftObject (Private)
    
    - (instancetype)initWithMin:(int)min max:(int)max;
    
    @end
    

    Now your Swift code won't be able to refer to the constructor (because it has private access modifier), while the Objective-C code can use it just fine.