My solution for Chapter 5 Annotations Extras Challenge:


#1

Here is my solution:

Here is MapPoint.h

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface MapPoint : NSObject <MKAnnotation>
{
    NSString *title;
    NSString *subtitle;
    CLLocationCoordinate2D coordinate;
}

//A new designated initializer for instances of MapPoint
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subtitle:(NSString *)d;

//This is a required property from MKAnnotation
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;

//This is an optional property from MKAnnotation
@property(nonatomic, copy) NSString *title, *subtitle;

@end

Here is MapPoint.m

[code]#import “MapPoint.h”

@implementation MapPoint

@synthesize coordinate, title, subtitle;

-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subtitle:(NSString *)d
{
self = [super init];

if(self)
{
    coordinate = c;
    [self setTitle:t];
    [self setSubtitle:d];
}

return self;

}

-(void)dealloc
{

[title release];
[super dealloc];

}
@end
[/code]

Here is WhereamiAppDelegate.h:

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

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

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

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

@end

Here is WhereamiAppDelegate.m

//
//  WhereamiAppDelegate.m
//  Whereami
//
//  Created by Scott Nelson on 2/6/12.
//  Copyright (c) 2012 NA. All rights reserved.
//

#import "WhereamiAppDelegate.h"

@implementation WhereamiAppDelegate

@synthesize window = _window;



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Create location manager object
    locationManager = [[CLLocationManager alloc] init];
    
    //Set the delegate of the location manager
    [locationManager setDelegate:self];
    
    //We want all results from the location manager
    [locationManager setDistanceFilter:kCLDistanceFilterNone];
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    
    //Show users location on the map
    [worldView setShowsUserLocation:YES];

    [[self window] makeKeyAndVisible];
    return YES;
}

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"%@", newLocation);
    
    //How many seconds ago was this new location created?
    NSTimeInterval t = [[newLocation timestamp] timeIntervalSinceNow];
    
    //CLLocationManagers will return the last found location of the
    //device first, you don't want that data in this case.
    //If this location was made more than 3 minutes ago, ignore it.
    if(t < -180)
    {
        //This is cached data, you don't want it, keep looking
        return;
    }
    
    [self foundLocation:newLocation];
}

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

//Used for zooming into Map
- (void)mapView:(MKMapView *)mapView 
    didUpdateUserLocation:(MKUserLocation *)userLocation
{
    CLLocationCoordinate2D loc = [userLocation coordinate];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
    [worldView setRegion:region animated:YES];
}

//Used for entering text
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [self findLocation];
    
    [textField resignFirstResponder];
    
    return YES;
}

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

-(void)foundLocation:(CLLocation *)loc
{
    CLLocationCoordinate2D coord = [loc coordinate];
    
    //Create date string
    NSDate *currentDate = [NSDate date];
    NSString *date = [NSDateFormatter localizedStringFromDate: currentDate
                                                    dateStyle:NSDateFormatterShortStyle 
                                                    timeStyle:NSDateFormatterShortStyle];
    
    //Create an instance of MapPoint with the current data
    MapPoint *mp = [[MapPoint alloc] initWithCoordinate:coord 
                                                  title:[locationTitleField text]
                                               subtitle:date];
    
    //Add it to the map view
    [worldView addAnnotation:mp];
    
    //MKMapview retains its annotations, we can release
    [mp release];
    
    //Zoom the region to this location
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
    [worldView setRegion:region animated:YES];
    
    [locationTitleField setText:@""];
    [activityIndicator stopAnimating];
    [locationTitleField setHidden:NO];
    [locationManager stopUpdatingLocation];
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
     If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
     */
}

- (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

#2

Looks really nice. Two quibbles:

  1. As the challenge calls for only the date (not date and time) you can suppress the time by using NSDateFormatterNoStyle for the timeStyle: when you’re creating your date in the foundLocation: method of WhereamiAppDelegate.m:
  1. In MapPoint.m, don’t you need to release subtitle in your dealloc method?

#3

Hey thanks for posting this solution, i was stuck on why my date is not converting to string, i was using this code in foundLocation method:

NSDate *date = [NSDate date];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

NSString *datestring = [formatter stringFromDate:date];

And for some reason datestring wasn’t converting into string with date… is it because i did not specify styles??

Also, i’ve learned that i don’t have to create new instance of NSDateFormatter, i can use method directly our of that class.

As always i overdid something lol Still learning too…

Glad for such a nice community here where you can turn for help to. Awesome.


#4

Since the timestamp is related to when the MapPoint is created, an alternative is to just add the date code to the MapPoint init method:

[code]-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];

if (self)
{
    coordinate = c;
    [self setTitle:t];
   
    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    [format setDateFormat:@"MMM dd, yyyy HH:mm"];
    NSDate *now = [[NSDate alloc] init];
    [self setSubtitle: [format stringFromDate: now]];

   [format release];
   [now release];
}

return self;

}
[/code]