0

I've read several posts similar to this one but I found them too specific. What I really want is a more general answer. According to Apple's view controller programming guide, viewDidLoad: should be used to "Allocating or loading data to be displayed in your view". If I have some data that has nothing to do with display, where should I initialize them?

Some posts suggests that initialization could be done in initWithCoder: when the view controller is initialized via a storyboard. I've tried to initialize an array in initWithCoder:, but after that it turned out that the array is still empty. So can we write a designated initializer to initialize this kind of data?

Here is the code:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        // load notes
        NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        _notes = [[PWCNotes alloc] initNotesWithFilename:self.docTitle path:path numberOfPages:self.numberOfPages];
        _index = 0;
    }

    return self;
}

Here is the designated initializer method for PWCNotes

- (id)initNotesWithFilename:(NSString *)fileName path:(NSString *)path numberOfPages:(int)numberOfPages
{
    if (!(self = [super init])) {
        return nil;
    }

    _filePath = [path stringByAppendingString:[NSString stringWithFormat:@"/%@/notes.txt", fileName]];

    BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:self.filePath];
    if (!exists)
    {
        // if file does not exist, create one and initialize the content
        _notes = [[NSMutableArray alloc] init];
        [[NSFileManager defaultManager] createFileAtPath:self.filePath contents:nil attributes:nil];
        NSString * emptyString = @"Add Notes Here!";
        for (int i = 0; i < numberOfPages; ++i)
        {
            [self.notes addObject:emptyString];
        }
        // write content of the array to the file
        [self.notes writeToFile:self.filePath atomically:YES];
    }
    else
    {
        // otherwise, load it from the text file
        _notes = [[NSMutableArray alloc] initWithContentsOfFile:self.filePath];
    }

    return self;
}

PWCNotes class has as a property a mutable array of NSString *s. When I call [self.notes.notes getObjectAtIndex:self.index], an NSRangeException is thrown, saying that I'm trying to access the object at index 0 in an empty array. Am I missing something?

ljiatu
  • 511
  • 7
  • 22
  • `initWithCoder:` should work. If you're having trouble with it, post some code to show what you're doing. (OTOH, if the data has nothing to do with display, maybe it shouldn't be in a view controller.) – Phillip Mills Mar 30 '14 at 03:27
  • Probably I should have said it the other way: it's not directly related to display. I'm not sure how related the data should be to be put into the `viewDidLoad:` method. – ljiatu Mar 30 '14 at 04:05
  • I've always loaded my data in viewDidLoad - if that's not the correct time and I need the data later, I use lazy loading which works well. I don't see the problem with using viewDidLoad though. – Robert J. Clegg Mar 30 '14 at 06:08
  • I don't see anywhere that notes.array is being allocated or having anything added. Did you mean self.notes.notes? – Phillip Mills Mar 30 '14 at 12:42
  • Yes I mean self.notes.notes. Sorry about the confusion. – ljiatu Mar 30 '14 at 14:34
  • @Tander There is probably no problem for it to work properly, but I think it's just better to have the work done at the most appropriate place. Per Apple's documentation, the `init` method should be the most appropriate place to have it done. – ljiatu Mar 30 '14 at 14:38
  • Try some logging. Print the value of `self` and `self.notes` at the end of the `initNotesWithFilename` method. Print the value of `self.notes` and `self.notes.notes` just before you hit the exception. What do you see? – Phillip Mills Mar 30 '14 at 14:51
  • notes is empty. I guess I know what the problem is. The class with the first `initWithCoder:` method is instantiated by a segue, and one of its properties is set in `prepareForSegue:`. I guess `initWithCoder:` is called before the segue is properly prepared, so `numberOfPages` ends up being 0. Nonetheless, should I initialize data in `initWithCoder:` anyway? – ljiatu Mar 30 '14 at 14:59

1 Answers1

0

viewDidLoad is the best place if you need to use the data only once the view appears, which is usually the case for View Controllers, as they only exists for managing views.

It's the best place because it is the one that's called in any case, no matter how the class got initialized.

If you really wanted to have the data ready earlier, you could implement an +initialize or +load method (NSObject +load and +initialize - What do they do?) instead, but that's not really what you should do in a View Controller.

Community
  • 1
  • 1
Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149