0

Okay I won't pretend to know everything about Objective-C and iOS programming, as I'm just getting started, but this one has me completely stumped. I have a class, ShoppingListViewController, and in that class, I override the initWithCoder Method to read:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if (self) {
        self.title = @"Shopping List";

        [self loadItems];
    }

    return self;
}

Within that loadItems method, there is a line that causes the app to crash on opening every time:

self.items = [NSMutableArray array];

The app crashes with the following error:

Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Could not load NIB in bundle:

However if I replace that line with the following:

_items = [NSMutableArray array];

Everything works fine. Now I understand that I am circumventing the default setters by doing this, but I'm unclear on why exactly the runtime has an issue with this normally, and why it's anything to do with NIB files? Could anyone enlighten me?

Updating with more info:

The items property is declared in the header of the class:

@property (nonatomic) NSArray *items;

And the loadItems method is pretty sparse and essentially that line is the only one that really matters on first load:

- (void)loadItems {
    NSString *filePath = [self pathForItems];

    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        self.items = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    } else {
        _items = [NSMutableArray array];
    }
}    
Popeye
  • 11,839
  • 9
  • 58
  • 91
Leon Aves
  • 739
  • 1
  • 7
  • 24

3 Answers3

1

You should not message self in init or dealloc. Read this article for a better explanation

This is because self.whatever will trigger other side effects, such as Key-Value Observing (KVO) notifications, or maybe your class implements (explicitly) or a subclass overrides setWhatever: -- and that could expose your partially initialized instance to other APIs (including its own), which rightly assume they are dealing with a fully constructed object.

You can refer to this answer for further information.

P.S. Do not ever forget that self.something invokes a setter/getter.

Community
  • 1
  • 1
gsach
  • 5,715
  • 7
  • 27
  • 42
1

I think that the default property setter might have some dependencies you don't know. ( Although I'm not sure ).

The init# family of methods is just for class initialization. Since iOS dev implies MVC development and loading the data is loading the model dependencies, they shouldn't be in the init functions.

I'd recommend to put the load functionality in viewDidLoad or similar methods that imply a ready state before having shown the view, since then you can be a 100% sure that the view controller is ready.

Do not put it into viewWillAppear or viewDidAppear since these could be called multiple times!

MABVT
  • 1,350
  • 10
  • 17
-1

First, calling properties in init method is not recommended, as they may not be ready yet.

Second, show the declaration of self.items property and the loadItems method.

Dvole
  • 5,725
  • 10
  • 54
  • 87