NS_DESIGNATED_INITIALIZER warnings

I programmatically create several tables and the code has worked fine for years. It did not generate any warnings two weeks ago when I last ran it. I’ve since updated to Xcode 8.3 and 10.10.3 and now get three warnings for each UITableViewController.


Method override for the designated initializer of the superclass '-initWithStyle:' not found.
Method override for the designated initializer of the superclass '-initWithCoder:' not found.
Method override for the designated initializer of the superclass '-initWithNibName:bundle:' not found.

The code to initialize the table is similar for all of my tables:


- (instancetype)initInManagedObjectContext:(NSManagedObjectContext *)context 
                 withScoreKeeper:(ScoreKeeper *)scorer 
                    withWordList:(WordList *)wordlist {

    self = [super initWithStyle:UITableViewStyleGrouped];

    if (self) {
        _mObjContext = context;
        _scoreKeeper = scorer;
        _wordList = wordlist;
    }
    return self;
}

and the .h looks like this:


@interface SettingsTableViewController : UITableViewController {
    UIPopoverController *popover;

}
    - (instancetype)initInManagedObjectContext:(NSManagedObjectContext *)context 
                     withScoreKeeper:(ScoreKeeper *)scorer 
                        withWordList:(WordList *)wordlist NS_DESIGNATED_INITIALIZER;

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.

From 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.

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, it was suggested that I use NSAssert() to 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;
}

Now 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

This stackoverflow question has some useful info.

This article explains more about why it is implemented.

Update: I found this article (UITableViewController Designated Initializer Woes) where they have a more complete explanation of the issue and a more complete fix.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.