Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically/Manually create a MKPlacemark/CLPlacemark

Problem

I have a set of placemark information (country, city, etc) and a Lat/Lon pair. I would like to use this to create an MKPlacemark object.


Discussion

It appears that this class can only be created by

- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary

whose docs state states

You can create placemark objects manually for entities for which you already have address information, such as contacts in the Address Book. Creating a placemark object explicitly avoids the need to query the reverse geocoder object for the same information.

Perfect! I have already reverse-geocoded and wish to avoid such a query. What can I add to the dictionary?

For a list of strings that you can use for the keys of this dictionary, see the “Address Property” constants in ABPerson Reference. All of the keys in should be at the top level of the dictionary.

Which shows relevant keys

const ABPropertyID kABPersonAddressProperty;
const CFStringRef kABPersonAddressStreetKey;
const CFStringRef kABPersonAddressCityKey;
const CFStringRef kABPersonAddressStateKey;
const CFStringRef kABPersonAddressZIPKey;
const CFStringRef kABPersonAddressCountryKey;
const CFStringRef kABPersonAddressCountryCodeKey;

This falls quite short of the base traits for an MKPlacemark:

Accessing the Location Data

  • location property

Accessing the Placemark Attributes

  • name property
  • addressDictionary property
  • ISOcountryCode property
  • country property
  • postalCode property
  • administrativeArea property
  • subAdministrativeArea property
  • locality property
  • subLocality property
  • thoroughfare property
  • subThoroughfare property
  • region property

Accessing Geographic Information

  • inlandWater property
  • ocean property

Accessing Landmark Information

  • areasOfInterest property

Fortunately, the actual header file for MKPlacemark's superclass says something about the address dictionary:

// address dictionary properties

@property (nonatomic, readonly) NSString *name; // eg. Apple Inc.

@property (nonatomic, readonly) NSString *thoroughfare; // street address, eg. 1 Infinite Loop

@property (nonatomic, readonly) NSString *subThoroughfare; // eg. 1

@property (nonatomic, readonly) NSString *locality; // city, eg. Cupertino

@property (nonatomic, readonly) NSString *subLocality; // neighborhood, common name, eg. Mission District

@property (nonatomic, readonly) NSString *administrativeArea; // state, eg. CA

@property (nonatomic, readonly) NSString *subAdministrativeArea; // county, eg. Santa Clara

@property (nonatomic, readonly) NSString *postalCode; // zip code, eg. 95014

@property (nonatomic, readonly) NSString *ISOcountryCode; // eg. US

@property (nonatomic, readonly) NSString *country; // eg. United States

@property (nonatomic, readonly) NSString *inlandWater; // eg. Lake Tahoe

@property (nonatomic, readonly) NSString *ocean; // eg. Pacific Ocean

@property (nonatomic, readonly) NSArray *areasOfInterest; // eg. Golden Gate Park

So, I create a dictionary and then pass it like so:

return [[[MKPlacemark alloc] initWithCoordinate:aLocation.coordinate addressDictionary:addressDictionary] autorelease];

Unfortunately, after all that, introspection shows that the information did not stick:

NSLog(@"placemark %@ from %@", placemark, addressDictionary);
NSLog(@"has %@", placemark.thoroughfare);

Prints

2012-01-31 20:14:22.545 [15450:1403] placemark <+___,-___> +/- 0.00m from {
administrativeArea = __;
postalCode = _____;
subAdministrativeArea = ___;
subThoroughfare = __;
thoroughfare = "_____";
}
2012-01-31 20:14:22.545[15450:1403] has (null)

Conclusion

So, I'm about at the end here. Has anyone figured out how to create your own MKPlacemark? Thanks.

like image 797
SG1 Avatar asked Feb 01 '12 02:02

SG1


1 Answers

You can subclass MKPlacemark:

In MyPlacemark.h

@interface MyPlacemark : MKPlacemark

extern NSString * const kCustomPlacemarkAddressThoroughfareKey;
extern NSString * const kCustomPlacemarkAddressSubThoroughfareKey;
extern NSString * const kCustomPlacemarkAddressLocalityKey;
extern NSString * const kCustomPlacemarkAddressSubLocalityKey;
extern NSString * const kCustomPlacemarkAddressAdministrativeAreaKey;
extern NSString * const kCustomPlacemarkAddressSubAdministrativeAreaKey;
extern NSString * const kCustomPlacemarkAddressPostalCodeKey;
extern NSString * const kCustomPlacemarkAddressCountryKey;
extern NSString * const kCustomPlacemarkAddressCountryCodeKey;

@end

In MyPlacemark.m:

#import "MyPlacemark.h"

@implementation MyPlacemark

NSString * const kCustomPlacemarkAddressThoroughfareKey = @"thoroughfare";
NSString * const kCustomPlacemarkAddressSubThoroughfareKey = @"subThoroughfare";
NSString * const kCustomPlacemarkAddressLocalityKey = @"locality";
NSString * const kCustomPlacemarkAddressSubLocalityKey = @"subLocality";
NSString * const kCustomPlacemarkAddressAdministrativeAreaKey = @"administrativeArea";
NSString * const kCustomPlacemarkAddressSubAdministrativeAreaKey = @"subAdministrativeArea";
NSString * const kCustomPlacemarkAddressPostalCodeKey = @"postalCode";
NSString * const kCustomPlacemarkAddressCountryKey = @"country";
NSString * const kCustomPlacemarkAddressCountryCodeKey = @"countryCode";

- (NSString *)thoroughfare
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressThoroughfareKey];
}

- (NSString *)subThoroughfare
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressSubThoroughfareKey];
}

- (NSString *)locality
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressLocalityKey];
}

- (NSString *)subLocality
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressSubLocalityKey];
}

- (NSString *)administrativeArea
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressAdministrativeAreaKey];
}

- (NSString *)subAdministrativeArea
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressSubAdministrativeAreaKey];
}

- (NSString *)postalCode
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressPostalCodeKey];
}

- (NSString *)country
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressCountryKey];    
}

- (NSString *)countryCode
{
    return [self.addressDictionary objectForKey:kCustomPlacemarkAddressCountryCodeKey];
}

@end

It looks ugly, but it's the only way so far that I've found to work.

like image 128
daLizard Avatar answered Oct 03 '22 04:10

daLizard