Silver Challenge - Close but no cigar


#1

Hi

Been driving me mad this one…In BNRMapPoint.h I made BNRMapPoint adhere to the NSCoding protocol and changed the coordinate property from readonly to readwrite. Then added the following coding methods in BNRMapPoint.m

[code]- (void)encodeWithCoder:(NSCoder *)aCoder
{
// Need to store coordinate and title
// coordinate is CLLocationCoordinate2D which is a C struct and can’t be archived
// So need to archive the individual longitude and latitude which are double’s
double coordLatitude = coordinate.latitude;
double coordLongitude = coordinate.longitude;

NSLog(@"ENCODING coordLatitude %f coordLongitude %f " ,coordLatitude, coordLongitude);
[aCoder encodeObject:title forKey:@"title"];
[aCoder encodeDouble:coordLatitude forKey:@"coordLatitude"];
[aCoder encodeDouble:coordLongitude forKey:@"coordLongitude"];

}

  • (id)initWithCoder:(NSCoder *)aDecoder
    {
    self = [super init];
    if (self) {
    double coordLatitude = [aDecoder decodeDoubleForKey:@“coordLatitude”];
    double coordLongitude = [aDecoder decodeDoubleForKey:@“coordLongitude”];

      NSLog(@"DECODING coordLatitude %f coordLongitude %f " ,coordLatitude, coordLongitude);
      
      [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
      
      coordinate = CLLocationCoordinate2DMake(coordLatitude, coordLongitude);
    

    }
    return self;
    }
    [/code]

In WhereamiViewController.h I added a local variable NSMutableArray *locationPoints and 2 methods - (NSString *)mpArchivePath and - (BOOL)saveMPs (both following the chapter 14 example). In WhereamiViewController.m I changed:

[code]- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    
    NSString *path = [self mpArchivePath];
    locationPoints = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    // If the array hasn't previously been saved, create a new empty one
    NSLog(@"locationPoints %@", locationPoints);
    if (!locationPoints) {
        NSLog(@"new one");
        locationPoints = [[NSMutableArray alloc] init];
    } else {
        // We have loaded the saved points
        // Now add the annotation to the map
        for (int i = 0; i < locationPoints.count; i++) {
            BNRMapPoint *mp = [locationPoints objectAtIndex:i];
            NSLog(@"%@: %f %f", mp.title, mp.coordinate.latitude, mp.coordinate.longitude);
            [worldView addAnnotation:mp];
        }
        //[worldView addAnnotations:locationPoints];
    }
}
return self;

}
[/code]

To foundLocation method, added:

// Add map point to array [locationPoints addObject:mp];

Added the 2 new methods:

[code]- (NSString *)mpArchivePath
{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:@“mp.archive”];
}

  • (BOOL)saveMPs
    {
    NSString *path = [self mpArchivePath];
    return [NSKeyedArchiver archiveRootObject:locationPoints toFile:path];
    }[/code]

The NSLogs show me that it’s encoding and saving the points correctly; decoding them correctly with the title and coordinate info coming in as expected. However, I just can’t get the annotations to appear on the map. Tried [worldView addAnnotation:mp]; and [worldView addAnnotations:locationPoints]; but nothing.

Any ideas about how to add the decoded BNRMapPoint objects to the map as annotations?

Am I going about this the right way? Do I need to create an BNRMapPointStore class?

Thanks, Mark


#2

As it happens, I did create a BNRMapPointStore in order to implement this challenge. But I don’t think that’s the problem you had with your solution. I noticed that you’d put the logic to addAnnotations for each archived BNRMapPoint into WhereamiViewController’s initWithNibName:bundle: method; this was the major difference between your solution and my (working) solution. I do this logic in viewDidLoad:

[code]- (void)viewDidLoad
{
[worldView setShowsUserLocation:YES];

NSMutableArray *allMapPoints = [[BNRMapPointStore sharedStore] allMapPoints];
for (BNRMapPoint *mp in allMapPoints) {
    [worldView addAnnotation:mp];
}

}
[/code]

When I changed my code to test doing addAnnotations in initWithNibName:bundle: like you did, it broke. I wish I could explain with certainty why this is the case, but I’m not there yet! :confused:


#3

Thanks for the reply dmddmd. (Sorry for my late one! :blush: )

Adding the code into viewDidLoad worked - thank you.

On reflection this seems a more sensible place to add the annotations, but still not sure why the code doesn’t work in the ibitWithNibName method? This method is definitely being called and the archived data returned is the same in both methods. I assume therefore it must be something to do with the addAnnotations method?? But it’s still a bit of a mystery to me! Thanks anyway - works great now - and in future I would use a store.

Mark


#4

Could some help with pointers as to what has gone wrong with my code? I have to admit i did some copying and pasting from the code here when it didn’t work out, I made a MapPointStore and then pulled the mapPoints from there onto the map but this doesn’t seemed to have work. I don’t get any error messages just no mapPoints, when I first put i into the background and then close the simulator and open it again. Any help would be apreciated

MapPointStore.h

[code]#import <Foundation/Foundation.h>
#import “BNRMapPoint.h”

@interface MapPointStore : NSObject
{
NSMutableArray *allPoints;
}

+(MapPointStore*) defaultStore;

-(BOOL) saveChanges;
-(NSString*) mapPointArchivePath;
-(BNRMapPoint*) createPointWithCoordinate: (CLLocationCoordinate2D)c title:(NSString*)t;
-(NSMutableArray*) allPoints;

@end[/code]

MapPointStore.m

[code]#import “MapPointStore.h”
#import “BNRMapPoint.h”

@implementation MapPointStore

+(MapPointStore*) defaultStore
{
static MapPointStore *defaultStore = nil;

if (!defaultStore)
    defaultStore = [[super allocWithZone:nil] init];

return defaultStore;

}

+(id) allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}

  • (id)init
    {
    self = [super init];
    if (self) {

      NSString *path = [self mapPointArchivePath];
      allPoints = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
      
      if (!allPoints) {
          allPoints = [[NSMutableArray alloc] init];
      }
    

    }
    return self;
    }

-(BNRMapPoint*) createPointWithCoordinate:(CLLocationCoordinate2D)c title:(NSString*)t
{
BNRMapPoint *mp = [[BNRMapPoint alloc] initWithCoordinate:c title:t];

[allPoints addObject:mp];

return mp;

}

-(NSMutableArray*) allPoints
{
return allPoints;
}

-(NSString*) mapPointArchivePath
{
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentDirectory = [documentDirectories objectAtIndex:0];

return [documentDirectory stringByAppendingPathComponent:@"mapPoint.archive"];

}

-(BOOL) saveChanges
{
NSString *path = [self mapPointArchivePath];
return [NSKeyedArchiver archiveRootObject:allPoints toFile:path];
}

@end[/code]

MapPoint.h

-(id) initWithCoder:(NSCoder *)aDecoder;
-(void) encodeWithCoder:(NSCoder *)aCoder;[/code]

MapPoint.m

[code]
-(id) initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        double latitude = [aDecoder decodeIntForKey:@"latitude"];
        double longitude = [aDecoder decodeIntForKey:@"longitude"];
        [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
        
        coordinate = CLLocationCoordinate2DMake(latitude, longitude);
    }
    return self;
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeInt:coordinate.latitude forKey:@"latitude"];
    [aCoder encodeInt:coordinate.longitude forKey:@"longitude"];
    [aCoder encodeObject:title forKey:@"title"];
}
[/code]

WhereAmiViewController.m

[code]- (void)viewDidLoad
{
    [worldView setShowsUserLocation:YES];
    
    NSMutableArray *allMapPoints = [[MapPointStore defaultStore] allPoints];
    for (BNRMapPoint *mp in allMapPoints) {
        [worldView addAnnotation:mp];
    }
}

-(void) foundLocation:(CLLocation *)loc
{
    CLLocationCoordinate2D coord = [loc coordinate];
    
    BNRMapPoint *mp = [[MapPointStore defaultStore] 
                       createPointWithCoordinate:coord 
                       title:[locationTitleField text]];
    
    [worldView addAnnotation:mp];
    
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
    
    [worldView setRegion:region animated:YES];
    
    [locationTitleField setText:@""];
    [activityIndicator stopAnimating];
    [locationTitleField setHidden:NO];
    [locationManager stopUpdatingLocation];
}

AppController.m

[code]- (void)applicationDidEnterBackground:(UIApplication *)application
{
BOOL success = [[MapPointStore defaultStore] saveChanges];

if (success) {
    NSLog(@"Saved all of the BNRItems");
}
else {
    NSLog(@"Could not save any of the BNRItems :(");
}

}[/code]


#5

@benne90:
maybe the problem is that you are encoding/decoding int values but need doubles for lat/lon?
My solution is very similar to yours otherwise and seems to work.


#6

Great that solved it thanks!

Changed it to encodeForDouble:

and decodeForDouble:

in MapPoint.m


#7

[quote=“BananaSkin”]
On reflection this seems a more sensible place to add the annotations, but still not sure why the code doesn’t work in the ibitWithNibName method? This method is definitely being called and the archived data returned is the same in both methods. I assume therefore it must be something to do with the addAnnotations method?? But it’s still a bit of a mystery to me! Thanks anyway - works great now - and in future I would use a store.
Mark[/quote]

I had the same problem (and the fact that I was archiving [worldView annotations] which is an array containing our BNRMapPoint but also MKUserLocation that can’t be archived).
Calling addAnnotations method in viewDidLoad solved it, thanks dmddmd !
And I still don’t get why it works in viewDidLoad but doesn’t in initWithNibName.
Thanks !


#8

Hi guys,
I think a much simple solution in initWithCoder and encodeWithCoder would be;

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

if (self)
{
    self.title = [aDecoder decodeObjectForKey:@"title"];
    
    coordinate.latitude = [aDecoder decodeDoubleForKey:@"latitude"];
    coordinate.longitude = [aDecoder decodeDoubleForKey:@"longitude"];
  
}

return self;

}
[/code]

There is no need to create double values and then create the coordinate again. We already have a property of the type CLLocationCoordinate2D, we just need to set its values.

Cheers


#9

I seem to have something wrong, but after 4 hours looking for it I just cant find it!!

I even did a nslog in viewDidLoad to check if the mp where being added to worldView and it seems they are!!..
And if I put a new MP is gets saved, and the next time you load the app the console will tell a one more MP added to worldView, but I just cant see them!!

Here is the code:

aH!!..and thanks for looking!!

Wherea_iAppDelegate.m

#import "Wherea_iAppDelegate.h"

#import "Wherea_iViewController.h"
#import "BNRMapPointStore.h"

@implementation Wherea_iAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[Wherea_iViewController alloc] initWithNibName:@"Wherea_iViewController" bundle:nil];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    BOOL success = [[BNRMapPointStore sharedStore] saveChanges];
    if (success) {
        NSLog(@"Saved all the MP");
    } else {
        NSLog(@"Could not save all MP");
    }
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

Wherea_iViewController.h


#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#import "BNRMapPointStore.h"

@interface Wherea_iViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate, UITextFieldDelegate>
{
    CLLocationManager *locationManager;
    
    
    IBOutlet UITextField *locationTitleField;
    IBOutlet UIActivityIndicatorView *activityIndicator;
    IBOutlet MKMapView *woldView;
}
@property(assign, nonatomic) CLLocationDistance distanceFilter;


- (void)findLocation;
- (void)foundLocation:(CLLocation *)loc;

- (IBAction)setMapType:(id)sender;


@end

Wherea_iViewController.m

[code]#import “Wherea_iViewController.h”
#import “BNRMapPoint.h”
#import “BNRMapPointStore.h”

@interface Wherea_iViewController ()
@end

@implementation Wherea_iViewController
@synthesize distanceFilter;

  • (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
    self = [super initWithNibName:nibNameOrNil
    bundle:nibBundleOrNil];
    if (self) {
    locationManager = [[CLLocationManager alloc]init];
    [locationManager setDelegate:self];
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [locationManager setDistanceFilter:kCLLocationAccuracyKilometer];

      // [locationManager startUpdatingLocation];
      
      [locationManager startUpdatingHeading];
    

    }
    return self;
    }

  • (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    {
    NSLog(@"%@", [locations lastObject]);
    CLLocation *newLocation = [locations lastObject];
    NSTimeInterval t = [[newLocation timestamp] timeIntervalSinceNow];

    if (t < -180) {
    return;
    }
    [self foundLocation:newLocation];
    }

  • (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
    {
    NSLog(@"%@", newHeading);
    }

-(void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(@“could not find location: %@”, error);
}

  • (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
    {
    mapView.mapType = 0;
    CLLocationCoordinate2D centerCoordinate = [userLocation coordinate];
    CLLocationDistance latitudinalMeters = 250;
    CLLocationDistance longitudinalMeters = 250;

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoordinate, latitudinalMeters, longitudinalMeters);
    [woldView setRegion:region animated:YES];
    }

  • (void)findLocation
    {
    [locationManager startUpdatingLocation];
    [activityIndicator startAnimating];
    [locationTitleField setHidden:YES];
    }

  • (void)viewDidLoad
    {
    [woldView setShowsUserLocation:YES];

    NSMutableArray *allMapPoints = [[BNRMapPointStore sharedStore] allMapPoints];
    for (BNRMapPoint *mp in allMapPoints) {
    [woldView addAnnotation:mp];
    NSLog(@“one mp on screen”);
    }
    }

  • (void)foundLocation:(CLLocation *)loc
    {
    CLLocationCoordinate2D coord = [loc coordinate];
    NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date]
    dateStyle:kCFDateFormatterShortStyle
    timeStyle:kCFDateFormatterShortStyle];

    NSString *tittleAndDate = [[locationTitleField text] stringByAppendingString:dateString];

    BNRMapPoint *mp = [[BNRMapPointStore sharedStore] createPointWithCoordinates:coord andTitle:tittleAndDate];
    [woldView addAnnotation:mp];

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
    [woldView setRegion:region];

    [locationTitleField setText:@""];
    [activityIndicator stopAnimating];
    [locationTitleField setHidden:NO];
    [locationManager stopUpdatingLocation];
    }

  • (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    [self findLocation];

    [textField resignFirstResponder];

    return YES;
    }

  • (IBAction)setMapType:(id)sender
    {

    switch (((UISegmentedControl *)sender).selectedSegmentIndex){
    case 0:
    {
    woldView.mapType = MKMapTypeStandard;
    break;
    }
    case 1:
    {
    woldView.mapType = MKMapTypeSatellite;
    break;
    }
    case 2:
    {
    woldView.mapType = MKMapTypeHybrid;
    }
    default:
    {
    woldView.mapType = MKMapTypeHybrid;
    break;
    }
    }
    }

  • (void)dealloc
    {
    [locationManager setDelegate:nil];
    }

@end[/code]

BNRMapPoint.h

[code]#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface BNRMapPoint : NSObject <MKAnnotation, NSCoding>
{

}

  • (id)initWithCoordinate:(CLLocationCoordinate2D)c
    title:(NSString *)t;

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;

@property (nonatomic, copy) NSString *mapPointKey;

  • (id)initWithCoder:(NSCoder *)aDecoder;

  • (void)encodeWithCoder:(NSCoder *)aCoder;

@end
[/code]

BNRMapPoint.m

#import "BNRMapPoint.h"

@implementation BNRMapPoint
@synthesize coordinate, title, mapPointKey;

- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
    self = [super init];
    if (self) {
        coordinate = c;
        [self setTitle:t];
       
    }
    return self;
}
- (id)init
{
    return [self initWithCoordinate:CLLocationCoordinate2DMake(43.07, -89.32)
                              title:@"Hometown"];
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeDouble:coordinate.latitude forKey:@"latitude"];
    [aCoder encodeDouble:coordinate.longitude forKey:@"longitude"];
    [aCoder encodeObject:title forKey:@"title"];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        double latitude = [aDecoder decodeFloatForKey:@"latitude"];
        double longitude = [aDecoder decodeFloatForKey:@"longitude"];
        coordinate:CLLocationCoordinate2DMake(latitude, longitude);
        [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
    }
    return self;
}

@end

BNRMapPointStore.h

#import <Foundation/Foundation.h>
#import "BNRMapPoint.h"

@interface BNRMapPointStore : NSObject 
{
    NSMutableArray *allMapPoints;
}
+ (BNRMapPointStore *)sharedStore;

- (BNRMapPoint *)createPointWithCoordinates:(CLLocationCoordinate2D)c andTitle:(NSString *)s;

- (NSMutableArray *)allMapPoints;

- (NSString *)mapPointsArchivePath;

- (BOOL)saveChanges;

@end

BNRMapPointStore.m

[code]#import “BNRMapPointStore.h”
#import “BNRMapPoint.h”

@implementation BNRMapPointStore

  • (id)allocWithZone:(NSZone *)zone
    {
    return [self sharedStore];
    }

  • (BNRMapPointStore *)sharedStore
    {
    static BNRMapPointStore *shareStore = nil;
    if (!shareStore) {
    shareStore = [[super allocWithZone:nil] init];
    }
    return shareStore;
    }

  • (id)init
    {
    self = [super init];
    if (self) {
    NSString *path = [self mapPointsArchivePath];
    allMapPoints = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

      if (!allMapPoints) {
          allMapPoints = [[NSMutableArray alloc] init];
      }
    

    }
    return self;
    }

  • (NSMutableArray *)allMapPoints
    {
    return allMapPoints;
    }

  • (NSString *)mapPointsArchivePath
    {
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentDirectories objectAtIndex:0];
    return [documentDirectory stringByAppendingPathComponent:@“mapPoint.archive”];
    }

  • (BOOL)saveChanges
    {
    NSString *path = [self mapPointsArchivePath];

    return [NSKeyedArchiver archiveRootObject:allMapPoints toFile:path];
    }

  • (BNRMapPoint *)createPointWithCoordinates:(CLLocationCoordinate2D)c andTitle:(NSString *)s
    {
    BNRMapPoint *newPoint = [[BNRMapPoint alloc] initWithCoordinate:c title:s];
    [allMapPoints addObject];
    return newPoint;
    }

@end[/code]


#10

Funny that when I do the same without an array of MapPoints, but saving just one recent point, it doesn’t work (I don’t get my point loaded back). But works fine when I change archiving mp to archiving array.
Don’t really get why…


#11

Hi Everyone,

I’ve been scratching my head over this “silver challenge” also. I create a savedMapPoint property in the Whereami.h file which was loaded with the archived info. After checking that the map point was correctly saved and loaded ( and the addAnnotation message was been called in the viewDidLoad method as above ) . I was still getting the default starting point and not the point that I had saved.

I decided to “log” the methods in order to figure out what was going on than I got:

2013-03-11 18:30:09.843 Whereami[618:13d03] viewDidLoad
2013-03-11 18:30:09.847 Whereami[618:13d03] viewWillAppear
2013-03-11 18:30:10.707 Whereami[618:13d03] mapView:didUpdateUserLocation

Then I got the default mapPoint. I solved using the “dirty trick” of adding a BOOL variable isFirstLocation to supress the behaviour of mapView:didUpdateUserLocation at the first call. Seems to me, after reading this thread that this is messy and unecessary. Any ideias on why this is happening?


#12

benne90, when you say MapPoint.h and MapPoint.m, do you mean BNRMapPoint, or is MapPoint another new class? And what is “AppController”? Is this another new class?

[quote=“benne90”]Could some help with pointers as to what has gone wrong with my code? I have to admit i did some copying and pasting from the code here when it didn’t work out, I made a MapPointStore and then pulled the mapPoints from there onto the map but this doesn’t seemed to have work. I don’t get any error messages just no mapPoints, when I first put i into the background and then close the simulator and open it again. Any help would be apreciated

MapPointStore.h

[code]#import <Foundation/Foundation.h>
#import “BNRMapPoint.h”

@interface MapPointStore : NSObject
{
NSMutableArray *allPoints;
}

+(MapPointStore*) defaultStore;

-(BOOL) saveChanges;
-(NSString*) mapPointArchivePath;
-(BNRMapPoint*) createPointWithCoordinate: (CLLocationCoordinate2D)c title:(NSString*)t;
-(NSMutableArray*) allPoints;

@end[/code]

MapPointStore.m

[code]#import “MapPointStore.h”
#import “BNRMapPoint.h”

@implementation MapPointStore

+(MapPointStore*) defaultStore
{
static MapPointStore *defaultStore = nil;

if (!defaultStore)
    defaultStore = [[super allocWithZone:nil] init];

return defaultStore;

}

+(id) allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}

  • (id)init
    {
    self = [super init];
    if (self) {

      NSString *path = [self mapPointArchivePath];
      allPoints = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
      
      if (!allPoints) {
          allPoints = [[NSMutableArray alloc] init];
      }
    

    }
    return self;
    }

-(BNRMapPoint*) createPointWithCoordinate:(CLLocationCoordinate2D)c title:(NSString*)t
{
BNRMapPoint *mp = [[BNRMapPoint alloc] initWithCoordinate:c title:t];

[allPoints addObject:mp];

return mp;

}

-(NSMutableArray*) allPoints
{
return allPoints;
}

-(NSString*) mapPointArchivePath
{
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentDirectory = [documentDirectories objectAtIndex:0];

return [documentDirectory stringByAppendingPathComponent:@"mapPoint.archive"];

}

-(BOOL) saveChanges
{
NSString *path = [self mapPointArchivePath];
return [NSKeyedArchiver archiveRootObject:allPoints toFile:path];
}

@end[/code]

MapPoint.h

-(id) initWithCoder:(NSCoder *)aDecoder;
-(void) encodeWithCoder:(NSCoder *)aCoder;[/code]

MapPoint.m

[code]
-(id) initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        double latitude = [aDecoder decodeIntForKey:@"latitude"];
        double longitude = [aDecoder decodeIntForKey:@"longitude"];
        [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
        
        coordinate = CLLocationCoordinate2DMake(latitude, longitude);
    }
    return self;
}

-(void) encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeInt:coordinate.latitude forKey:@"latitude"];
    [aCoder encodeInt:coordinate.longitude forKey:@"longitude"];
    [aCoder encodeObject:title forKey:@"title"];
}
[/code]

WhereAmiViewController.m

[code]- (void)viewDidLoad
{
    [worldView setShowsUserLocation:YES];
    
    NSMutableArray *allMapPoints = [[MapPointStore defaultStore] allPoints];
    for (BNRMapPoint *mp in allMapPoints) {
        [worldView addAnnotation:mp];
    }
}

-(void) foundLocation:(CLLocation *)loc
{
    CLLocationCoordinate2D coord = [loc coordinate];
    
    BNRMapPoint *mp = [[MapPointStore defaultStore] 
                       createPointWithCoordinate:coord 
                       title:[locationTitleField text]];
    
    [worldView addAnnotation:mp];
    
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
    
    [worldView setRegion:region animated:YES];
    
    [locationTitleField setText:@""];
    [activityIndicator stopAnimating];
    [locationTitleField setHidden:NO];
    [locationManager stopUpdatingLocation];
}

AppController.m

[code]- (void)applicationDidEnterBackground:(UIApplication *)application
{
BOOL success = [[MapPointStore defaultStore] saveChanges];

if (success) {
    NSLog(@"Saved all of the BNRItems");
}
else {
    NSLog(@"Could not save any of the BNRItems :(");
}

}[/code][/quote]


#13

I know this is an old thread, but for anyone still confused about why you have to restore the map point annotations in viewDidLoad instead of initWithNibName, remember the order that view controllers load their views- first the XIB, then all subviews (including worldView). worldView doesn’t exist yet during initWithNibName. You can verify by adding the following code to initWithNibName:

if(worldView){ NSLog(@"worldView exists"); } else{ NSLog(@"worldView doesn't exist yet"); }
Then try it in viewDidLoad.