Challenge - archiving MapPoint objects


#1

I have some misunderstanding about archiving, and this challenge is welcome to fill the holes. But, unfortunately, I am stucked at the point defining root object, so please help. As it is written: “The root object must be an instance of a class that conforms to NSCoding.” I suppose it should be NSMutableArray, which will hold mapPoints class instances, or I missed something? The problem is that I have no idea how to make a correlation between that array and encoded things, and it is exactly the hole for misunderstand archiving. Any suggestion in right direction is welcome!

Added in MapPoint.h:

float latituda; float longituda;
and

@property (nonatomic) float latituda; @property (nonatomic) float longituda;

Added in init method of MApPoint.m:

latituda = coordinate.latitude; longituda = coordinate.longitude;

Added required methods in MapPoint.m:

[code]-(void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeFloat:latituda forKey:@“Latituda”];
[aCoder encodeFloat:longituda forKey:@“Longituda”];
[aCoder encodeObject:title forKey:@“Naslov”];
}

-(id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
[self setLatituda:[aDecoder decodeFloatForKey:@“Latituda”]];
[self setLongituda: [aDecoder decodeFloatForKey:@“Longituda”]];
[self setTitle:[aDecoder decodeObjectForKey:@“Naslov”]];
}
return self;
}[/code]

I also created a new class like FileHelpers for defining path staff.


#2

I just completed this assignment so I’ll try to help you out, but keep in mind that I’m still learning like you and it might not be entirely correct. :slight_smile:

So yes, you should use an NSMutableArray to have a container with all the MapPoints. But as it states in the book, all instance variables of the object being archived have to implement the NSCoding protocol too. Obviously you already implemented the methods, being encodeWithCoder: and initWithCoder:, but in MapPoint.h you also have to add the protocol.

Okay, now we’ll move our attention to our application’s delegate, “WhereAmIAppDelegate.h”. As discussed we’ll need an NSMutableArray to store our MapPoints in, so we’ll create one here. We’ll also create a method that creates the array for us, either from file or new. And, to keep in line with the HomePwner exercise I’ve also created a method to get the path to our archive.

@interface WhereamiAppDelegate : NSObject 
    <UIApplicationDelegate, CLLocationManagerDelegate, MKMapViewDelegate, UITextFieldDelegate, MKReverseGeocoderDelegate> {
    CLLocationManager *locationManager;
    IBOutlet MKMapView *worldView;
    IBOutlet UITextField *locationTitleField;
    IBOutlet UIActivityIndicatorView *activityIndicator;
    NSMutableArray *locations;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

-(void)findLocation;
-(void)foundLocation:(CLLocation *)aLocation;
-(NSString *)mapPointsArchivePath;
-(void)getLocationData;

@end

Now for the implementation in WhereAmIAppDelegate.

In application:didFinishLoadingWithOptions: I’ve added a call to [self getLocationData]; to initialize our array, it’ll check if there are locations in our archive and load them if necessary. If not it will just create an empty NSMutableArray.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self getLocationData];
    … more code…
}
-(void)getLocationData {
    if(!locations) {
        locations = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self mapPointsArchivePath]] retain];
        NSLog(@"Trying to get locations from archive");
        
        if([locations count] > 0) {
            //adding older locations to map
            [worldView addAnnotations:locations];
        }
    }
    
    if(!locations) {
        //first run, file not present
        NSLog(@"Or not, locations file did not exist");
        locations = [[NSMutableArray alloc] init];
    }
}

-(NSString *)mapPointsArchivePath {
    NSLog(@"%@", pathInDocumentDirectory(@"mapPoints.data"));
    return pathInDocumentDirectory(@"mapPoints.data");
}

Now we need to make sure the location the user entered is added to our locations array. I put this in the reverseGeoCoder:didFindPlacemark: method, but if I remember correctly this was a challenge. So for people who didn’t complete that challenge it’ll be in foundLocation:.

And at the very last I made sure applicationDidEnterBackground: and applicationWillTerminate: both made sure to write the locations array to archive via:

Don’t forget to release locations in your dealloc.