Just in case anyone wants to know more about the error, here’s what I found out. I am not a programmer, so parts could be mistaken.
When I opened my project for the first time with Xcode 5 and Xcode 6, I was prompted to "Convert to Modern Objective-C Syntax". (The latest version of Xcode puts it under Edit > Convert > Convert to Modern Objective-C Syntax.) I allowed Xcode to convert everything and understood most of the changes. I understood how NS_DESIGNATED_INITIALIZER works but not why it works. Since I had no compiler errors and everything worked as before, I promptly forgot about it. In the latest version of Xcode, they appear to have updated the compiler and that’s what triggered my warning message.
In Apple’s notes: Adopting Modern Objective C
Using this macro introduces a few restrictions:
The implementation of a designated initializer must chain to a
superclass init method (with [super init...]) that is a designated
initializer for the superclass.
The implementation of a convenience initializer (an initializer not
marked as a designated initializer within a class that has at least
one initializer marked as a designated initializer) must delegate to
another initializer (with [self init...]).
If a class provides one or more designated initializers, it must
implement all of the designated initializers of its superclass.
Here’s what I think happened. First, I got three warning messages because UITableViewController has three designated initializers.
> - (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
> - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil NS_DESIGNATED_INITIALIZER;
> - (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
I violated the third restriction because I did not implement all of the designated initializers of the superclass.
Removing the NS_DESIGNATED_INITIALIZER macro from the .h files made the warnings go away.
The question then arises, Do I care that these classes have no designated initializers? Probably not.
First, there are no other initializers in these classes, so I won’t accidentally call the wrong one. Second, I’m not a programmer by training, so when I started writing apps, I used the procedural programming style that I was used to. Until recently, I had never subclassed a class. So I won’t be subclassing this one and there won’t be any subclasses to worry about. Now that I know a bit more about Objective C, it turns out that every class I wrote was a subclass of one of iOS’s classes and that actually explains a bit about why I was getting the errors.
To address Rob’s point. I did not realize that I could create the table view object by calling a method on its superclass. For example, this call works:
SettingsTableViewController *stvc = [[SettingsTableViewController alloc] initWithStyle: UITableViewStyleGrouped];
It works even when I have NS_DESIGNATED_INITIALIZER set. Presumably no other warnings are sent because the compiler is already complaining about not calling a designated initializer of super.
And as long as the views called in the table view do not need any of the objects that were passed in, everything is fine. If a view that is linked to in the table does need one of the objects, then obviously the app crashes.
Since I never want to call anything but the designated initializer, following Rob’s suggestion of using NSAssert(), I can make sure that I don’t call the designated initializers of my superclass, and make all the warnings go away with this code:
- (instancetype)initWithStyle:(UITableViewStyle)style {
NSAssert(NO, @"%@", @"Tried to implement with initWithStyle");
self = [self initInManagedObjectContext:nil withScoreKeeper:nil withWordList:nil];
return self;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
NSAssert(NO, @"%@", @"Tried to implement with initWithNibName");
self = [self initInManagedObjectContext:nil withScoreKeeper:nil withWordList:nil];
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
NSAssert(NO, @"%@", @"Tried to implement with initWithCoder");
self = [self initInManagedObjectContext:nil withScoreKeeper:nil withWordList:nil];
return self;
}
I get this error in the log when I try to call initWithStyle directly.
*** Assertion failure in -[SettingsTableViewController initWithStyle:],
/Users/jscarry/Words/Words/Settings/SettingsTableViewController.m:37
Useful links:
iOS Designated Initializers : Using NS_DESIGNATED_INITIALIZER
This article explains more about why it is implemented.