ObjC parent class with forward declaration in designated initializer has no accessible initializers

This is a behaviour that has changed between Swift 3 and Swift 4. I don’t know if this is a bug, or improved correctness. Before I submit a bug I wanted some feedback.

Example 1
Given this Objective-C header of a class that has a designated initializer that has a parameter that is a forward declared class:

@class ForwardDeclaredClass;

@interface Example : NSObject
- (nonnull instancetype)initWithForwardDeclaredClass:(nonnull ForwardDeclaredClass *)forwardDeclaredClass NS_DESIGNATED_INITIALIZER;
@end

Subclassing this type in Swift 3 (tested on up to 3.3) will still have init from NSObject accessible.

class ExampleSubclass: Example { }
let baseclass = Example()
let subclass = ExampleSubclass()

In Swift 4 however, initializers are no longer accessible, the last line above now has the error 'ExampleSubclass' cannot be constructed because it has no accessible initializers.

If we remove the forward declared class, there is no change. That is what makes me think this is a bug.


Example 2
Given this Objective-C header of a class that has a designated initializer that has a parameter that is a forward declared class and a parameter that is not. It also has a convenience initializer without the forward declared parameter:

@interface ExampleWithOtherParameters : NSObject

// must be set on initialisation
@property (nonatomic, copy) NSString *string;

- (instancetype)initWithString:(NSString *)string forwardDeclaredClass:(ForwardDeclaredClass *)forwardDeclaredClass NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithString:(NSString *)string;

@end

Subclassing this type in Swift 3 will still have init from NSObject accessible, as well as the convenience initializer.

class ExampleSubclassWithOtherParameters: ExampleWithOtherParameters { }
let baseclass = ExampleWithOtherParameters(string: "Test")
let subclass = ExampleSubclassWithOtherParameters()
let subclass2 = ExampleSubclassWithOtherParameters(string: "Test")

In Swift 4, the last two lines have the same error: 'ExampleSubclassWithOtherParameters' cannot be constructed because it has no accessible initializers.

We can get the Swift 3 behaviour back by altering the Objective-C class to have all initializers designated or none at all, designated initializers should only invoke a designated initializer on super, so we can’t get resuse out of the original designated initializer anymore (warning), and if we remove designated we don’t get correctness features anymore.

What do you think? Happy to answer any questions or provide further examples.

1 Like

First of all, thank you for this. Just ran into this problem and your post helped me get to somewhat of a resolution for tonight. I'm currently resolving it by adding the deps that were missing (fwd declared in the objC file.) in the Swift file throwing this error.