Bronze Challenge Solution without State Preservation/Restora


#1

As i have read so far, most of answers for Bronze Challenge solution is achieved by studying Application State Preservation/Restoration with complaint of the author’s mistake to raise such challenge by the end of this chapter. Yet I believe this Challenge can be solved using fundamental knowledge learned in the previous chapters. In fact, to this point of the book, I think most of us are already familiar with NSArray and writeToFile: automatically: method.

So since I did give it a try and succeeded, I would like share this with everyone, and also take the chance to seek improvement for my code, because there are still few things I dont seem to fully understand .

First of all, the logic of the solution (the algorithm)
1. We need an array to hold all the coordinate value of drawn lines
2. Write the array to a file before the Application does terminate (a PROPERTY LIST)
3. During application launch, load the property list and redraw the lines following coordinates that were saved.

*Extra feature: for further testing, I decided to implement a method where a user’s long touch can delete all the lines that has been drawn to the view

CODES IMPLEMENTED:

  1. Declare 2 voids in BNRDrawView.h, one for saving the lines and the other for reloading them at app launch

@interface BNRDrawView : UIView -(void)saveAllLines; -(void)redrawSavedLines; @end

…and their Implementations:

[code]-(void)saveAllLines
{
// Create a new array to hold cordinates of exisiting lines
NSMutableArray *lineToBeSaved = [[NSMutableArray alloc]init];
for (BNRLine *line in self.finishedLines) {
[lineToBeSaved addObject:[[NSNumber alloc]initWithFloat:line.begin.x]];
[lineToBeSaved addObject:[[NSNumber alloc]initWithFloat:line.begin.y]];
[lineToBeSaved addObject:[[NSNumber alloc]initWithFloat:line.end.x]];
[lineToBeSaved addObject:[[NSNumber alloc]initWithFloat:line.end.y]];
}

// Write all cordinates to a property list
[lineToBeSaved writeToFile:@"/Users/Elderaine/Desktop/Lines/_lines" atomically:YES];

// For every line needs 4 foat values as its cordinate, check to see how many lines saved to the property list
NSLog(@"%lu lines were saved to disk!",(lineToBeSaved.count)/4);

}

-(void)redrawSavedLines
{
// Create a new array to hold imported saved lines’ coordinate data
NSMutableArray *lineToBeDrawn = [[NSMutableArray alloc]initWithContentsOfFile:@"/Users/Elderaine/Desktop/Lines/_lines"];
if (lineToBeDrawn.count<4) { // If the number of entries is less than 4, then no line should be drawn
return;
}

// Double check the number of lines imported
NSLog(@"Imported %lu lines from savefile",(lineToBeDrawn.count)/4);

// Adding them to the finishedLines array of self, the method drawRect shall automatically take care of the drawing work
for (int i = 0; i < (lineToBeDrawn.count - 3); i += 4) {
    BNRLine *linex = [[BNRLine alloc]init];
    linex.begin = CGPointMake([lineToBeDrawn[i] floatValue], [lineToBeDrawn[i+1] floatValue]);
    linex.end = CGPointMake([lineToBeDrawn[i+2] floatValue], [lineToBeDrawn[i+3] floatValue]);
    [self.finishedLines addObject:linex];
}

}[/code]

In BNRDrawViewController.h class extension, create a pointer to BNRDrawView so I can call the newly added method later. Implement them:

[code]@interface BNRDrawViewController ()
@property (nonatomic) BNRDrawView *viewToDraw;
@end

@implementation BNRDrawViewController

  • (void)loadView
    {
    _viewToDraw = [[BNRDrawView alloc]initWithFrame:CGRectZero];
    [_viewToDraw redrawSavedLines]; // call the method to reload all saved lines
    self.view = _viewToDraw;
    }

-(void)viewWillDisappear:(BOOL)animated //before disappearance, call the method to save all drawn lines
{
if (animated == YES) {
[self.viewToDraw saveAllLines];
}
}

[/code]

In BNRAppDelegate.h, add one more line of code:

- (void)applicationDidEnterBackground:(UIApplication *)application { [self.window.rootViewController viewWillDisappear:YES]; // Call to the line-saving method of BNRDrawViewController }


So far, it works, except one thing: as I run it in the Simulator, everytime I run the app from Xcode and manually terminate it with the Simulator, an exception is thrown without description, pointing to main.h. When I stop the run in Xcode but keep using the app in the Simulator, it works fine. Explain?
Besides, I would like to know if there is any unnecessary line in my code. It seems quite long to me.


#2

You can expand the path to your saved files using for instance:
[@"~/Documents/lines" stringByExpandingTildeInPath]
to make the path more general.