NSObject subclasses don't allow changing the designated initializer in Obj-C with NS_DESIGNATED_INITIALIZER
| Originator: | info | ||
| Number: | rdar://22885942 | Date Originated: | 28-Sep-2015 02:28 PM |
| Status: | Open | Resolved: | |
| Product: | Developer Tools | Product Version: | Xcode 7.0 |
| Classification: | Serious Bug | Reproducible: | Always |
Summary:
When creating a new Objective-C subclass it’s often useful to replace the previous designated initializer (-init) with a new one. Example:
NS_ASSUME_NONNULL_BEGIN
@interface NewClass: NSObject
- (instancetype)initWithString:(NSString *)string NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
@implementation NewClass
- (instancetype)initWithString:(NSString *)string {
if ((self = [super init]]) { // correctly delegating to parent’s designated initializer
// etc
}
return self;
}
However, this does not compile.
Steps to Reproduce:
- Create an empty OS X or iOS project.
- Compile that code.
Expected Results:
- Code compiles, and NewClass only has one initializer: -initWithString:
Actual Results:
- Code fails to compile with the error: “Method override for the designated initializer of the superclass '-init' not found”
Regression:
1. This is inconsistent with Swift, where the behavior makes more sense: it’s not necessary to override the parent designated initializer if you’re replacing it with something else. You do, of course, have to call it in your new designated initializer like I’m doing here.
2. I’ve previously dealt with this issue (since in Objective-C you can’t guarantee that - [NewClass init] will never be called at runtime) by overriding it this way:
- (instancetype)init {
return [self initWithString:nil];
}
- (instancetype)initWithString:(NSString *)string {
NSParameterAssert(string);
}
Effectively catching this incorrect usage of the API at runtime. However, this is now impossible due to the explicit nullability annotations (NS_ASSUME_NONNULL_BEGIN): there is no way to follow the compilation error and actually implement -init in a way that it delegates to the new designated initializer (which is mandatory). Yes, I could do [self initWithString:@“”], but with more complex initializers it doesn’t make sense to create “dummy” objects just to please the compiler.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!