NSXML Parsing with Rest api and Mapview with Annotation?


Hi,

Today I am going to explain you How to perform Parsing with NSXML and How to show annotation in MKMapView.

Here I am Taking 1 UITextField and 1 UIButton.Whatever city name you will enter in the Textfield and Press Button it will show you in MKMapView with Annotation.

Step 1: Add Frameworks

1.CoreLocation

2.MapKit

step 2: Add Files

1.Place.h and Place.m

2.PlaceMark.h and PlaceMark.m (I will Provide).

step 3: Import Files in your view controller’s header file  and Declare Variables as shown in the Screenshots.

step 4: @synthesize all Variables as shown.

Step 5: Take NSString with Rest api and provide the textfield value to it.Make the connection with URL Request as shown.

NSString *strUrl = [NSString stringWithFormat:@”http://maps.googleapis.com/maps/api/geocode/xml?address=%@&sensor=false”,self.txtSearch.text];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:strUrl]] delegate:self];

check the connection object

if(conn)
self.data = [[NSMutableData data] init];

Step 6:Implement all the connection Methods as shown.

#pragma mark – Connection Delegates Methods

– (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@”Error ==>%@”,error);

}
– (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{

}

– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.data appendData:data];

}
– (void)connectionDidFinishLoading:(NSURLConnection *)connection{
//Standard NSXMLParser – SAX Parser
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:self.data];
parser.delegate=self;
[parser parse];
}
Step 7:Now Implement Parsing Methods with Root Tag and Object Tag so it will give’s you all the tags.

#pragma mark – NSXML Parsing Delegates Methods

// Document handling methods
// sent when the parser begins parsing of the document.
– (void)parserDidStartDocument:(NSXMLParser *)parser{

}
// sent when the parser finds an element start tag.
– (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if([elementName isEqualToString:@”GeocodeResponse“])
self.arrResult = [NSMutableArray array];
else if ([elementName isEqualToString:@”result“])
self.dMain = [NSMutableDictionary dictionary];
}
– (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
self.strings=string;
}

// sent when an end tag is encountered. The various parameters are supplied as above.
// sent when the parser has completed parsing. If this is encountered, the parse was successful.
– (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqualToString:@”GeocodeResponse“]){

}else if ([elementName isEqualToString:@”result“])
{
[self.arrResult addObject:self.dMain];
self.dMain=nil;
}else {
[self.dMain setObject:self.strings forKey:elementName];
}
}

Step 7:In parserDidEndDocument method you will get all the value whatever you required.Here I am getting Latitude/Longitude and Address as shown.

=> Make the object of Place class and Provide the parameter also make the object of PlaceMark and Provide the object of place class and Add the Placemark object to MapView as an Annotation.

– (void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@”Array = %@”,self.arrResult);

float latitude= [[[self.arrResult objectAtIndex:0] valueForKey:@”lat”] floatValue];
float longitude=[[[self.arrResult objectAtIndex:0] valueForKey:@”lng”] floatValue];

Place* home = [[Place alloc] init];
home.name = [[self.arrResult objectAtIndex:0] valueForKey:@”formatted_address”];
home.latitude = latitude;
home.longitude = longitude;

PlaceMark *from = [[PlaceMark alloc] initWithPlace:home];
[self.mView addAnnotation:from];
[self centerMap];
}

Step 8:For Annotation here you have to Integrate MKMapView’s Annotation Delegate methods as shown.

#pragma mark – MapView Annotation

– (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
// if it’s the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;

// try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = @”AnnotationIdentifier”;
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor=MKPinAnnotationColorPurple;
return pinView;
}

You can download the sample code From Here.

 

 

 

Draw Route Between two location


Hi All,

Here I am going to explain you how to draw route using two latitude and Longitude.Here you have to consider if any Sea or River comes between 2 location then route drawing is not possible.

Step 1:Please check the following image for Framework required and predefined classes

if you want you will get all the files with sample code at the end of the post.

Step 2: Import Required files in your ViewController and Provide the 2 different Location’s Latitude and Longitude.Please follow this 2 images accordingly.

OutPut

You can Grab this code from Here:  

iPhone/iPad – Adding overlay


This blog is about adding custom overlay to a map. Overlays like polygon and circle can be added to the map. For instance you want to highlight or outline an area of a state or states in a country. In my application i have outlined all the states in US.

MKMapKit provides MKPolygon class and add overlay to achieve this. This can be done with easy four steps
1. Initialize map
2. Get coordinates
3. Create Polygon and add to map.
4. Implement delegate
1. Initialize Map :
Initialize the map view and add it as subview.

MKMapView _mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 28, 360, 250)];

MKCoordinateRegion region;

region.center.latitude = 42.5116;

region.center.longitude = -90.6290;

region.span.longitudeDelta = 26.0;

region.span.latitudeDelta = 26.0;

_mapView.showsUserLocation = NO;

[_mapView setScrollEnabled:YES];

[_mapView setRegion:region];

[_mapView setDelegate:self];

[self.view addSubview:_mapView];

2. Get Coordinates
Here in this example, i have outlined all the US states. So to draw a polygon we need coordinates of all the state. Coordinates can be saved in local file or local database. This is the link to get coordinates of all US state
3. CreatePolygon:
Below is the code to add polygon

NSMutableArray* points; (contains coordinates of particular state)

CLLocationCoordinate2D *coords =

malloc(sizeof(CLLocationCoordinate2D) * [points count]);

 

for(int idx = 0; idx < [points count]; idx++) {

CLLocation* location = [points objectAtIndex:idx];

coords[idx] = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);

}

polygon = [MKPolygon polygonWithCoordinates:coords count:[points count]];

free(coords);

[_mapView addOverlay:polygon];

 

3. Implement Delegate

 

 

– (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay

{

MKPolygonView *polygonView = [[[MKPolygonView alloc] initWithPolygon:overlay] autorelease];

polygonView.lineWidth = 0.5;

polygonView.strokeColor = [UIColor whitecolor];

polygonView.fillColor = [[UIColor colorWithRed:0.9176 green:0.9098 blue:0.8117 alpha:1.0] colorWithAlphaComponent:0.5];;

return polygonView;

}

 

zooming also taken care by this implementation. We dont need to do extra coding to handle zoom.

How to work with Core Motion Gyroscope?


It’s a simple app that utilizes Core Motion to roll an object on screen in the direction that the user is rolling the device. Hold the device upright (in portrait mode) and rotate clockwise/counter-clockwise.

You can grab the source code directly below:

Gyroscope.zip

iPad/iPhone forward geocoding API using Google geocoding service


This sample iPad application contains a search bar and a large UIMapView. Search results are visualized on the map with a placemark and by clicking the placemark the map will zoom to the viewport returned from the geocoding service. When I started working with the geocoding service it was still in version two, this last week Google launched version three. Version two will be depricated of course but I had already written the parser for version two so I’ve included it as well in my sample. Of course the API works for iPhone as well. Because the API contains quite a lot of code you will find the code inside the sample project at the bottom of this page.

- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {

	NSLog(@"Searching for: %@", searchBar.text);
	if(forwardGeocoder == nil)
	{
		forwardGeocoder = [[BSForwardGeocoder alloc] initWithDelegate:self];
	}

	// Forward geocode!
	[forwardGeocoder findLocation:searchBar.text];

}
-(void)forwardGeocoderFoundLocation
{
	if(forwardGeocoder.status == G_GEO_SUCCESS)
	{
		int searchResults = [forwardGeocoder.results count];

		// Add placemarks for each result
		for(int i = 0; i < searchResults; i++)
		{
			BSKmlResult *place = [forwardGeocoder.results objectAtIndex:i];

			// Add a placemark on the map
			CustomPlacemark *placemark = [[CustomPlacemark alloc] initWithRegion:place.coordinateRegion];
			placemark.title = place.address;
			[mapView addAnnotation:placemark];

			NSArray *countryName = [place findAddressComponent:@"country"];
			if([countryName count] > 0)
			{
				NSLog(@"Country: %@", ((BSAddressComponent*)[countryName objectAtIndex:0]).longName );
			}

			[countryName release];
		}

		if([forwardGeocoder.results count] == 1)
		{
			BSKmlResult *place = [forwardGeocoder.results objectAtIndex:0];

			// Zoom into the location
			[mapView setRegion:place.coordinateRegion animated:TRUE];
		}

		// Dismiss the keyboard
		[searchBar resignFirstResponder];
	}
}
 When search has executed the geocoder contains the result and a status code. The status code is from Google and to support both version 2 and 3 of the API there’s an enum containing response codes. If everything goes well the status should be “G_GEO_SUCCESS” and the “results” property will contain an array of BSKmlResult objects which contain the location information returned for the query. Here’s an example query for my home town Stockholm (Google geocoding service version 3) :http://maps.google.com/maps/api/geocode/xml?address=stockholm&sensor=false.
The details for the service can be found here:http://code.google.com/apis/maps/documentation/geocoding/.
There are multiple arguments you can pass to the search url, you should read the geocoding documentation and check the search url in the application before you implement this in your own app.

BSForwardGeocoder

#import <Foundation/Foundation.h>
#import "BSGoogleV2KmlParser.h"
#import "BSGoogleV3KmlParser.h"

// Enum for geocoding status responses
enum {
	G_GEO_SUCCESS = 200,
	G_GEO_BAD_REQUEST = 400,
	G_GEO_SERVER_ERROR = 500,
	G_GEO_MISSING_QUERY = 601,
	G_GEO_UNKNOWN_ADDRESS = 602,
	G_GEO_UNAVAILABLE_ADDRESS = 603,
	G_GEO_UNKNOWN_DIRECTIONS = 604,
	G_GEO_BAD_KEY = 610,
	G_GEO_TOO_MANY_QUERIES = 620
};

@protocol BSForwardGeocoderDelegate <NSObject>
@required
-(void)forwardGeocoderFoundLocation;
@optional
-(void)forwardGeocoderError:(NSString *)errorMessage;
@end

@interface BSForwardGeocoder : NSObject {
	NSString *searchQuery;
	NSString *googleAPiKey;
	int status;
	NSArray *results;
	id<BSForwardGeocoderDelegate> delegate;
}
-(id) initWithDelegate:(id<BSForwardGeocoderDelegate>)del;
-(void) findLocation:(NSString *)searchString;

@property (assign) id<BSForwardGeocoderDelegate> delegate;
@property (nonatomic, retain) NSString *searchQuery;
@property (nonatomic, readonly) int status;
@property (nonatomic, retain) NSArray *results;

@end

BSKmlResult
The result class is the same for both version 2 and 3 of the service. A big difference in the returned information between the versions is the way address components are returned, in version three more information is returned and therefore I’ve created another class to store the address component information. The properties: countryNameCode, countryName, subAdministrativeAreaName and localityName are for version two only. For version three all address information is stored in the “addressComponents” array (contains BSAddressComponent objects). Because there is really no reason to use version 2 anymore you probably want to remove this code for your own application.

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import "BSAddressComponent.h"

@interface BSKmlResult : NSObject {
	NSString *address;
	NSString *countryNameCode;
	NSString *countryName;
	NSString *subAdministrativeAreaName;
	NSString *localityName;
	float viewportSouthWestLat;
	float viewportSouthWestLon;
	float viewportNorthEastLat;
	float viewportNorthEastLon;
	float boundsSouthWestLat;
	float boundsSouthWestLon;
	float boundsNorthEastLat;
	float boundsNorthEastLon;
	float latitude;
	float longitude;
	float height;
	NSInteger accuracy;
	NSArray *addressComponents;
}

@property (nonatomic, retain) NSString *address;
@property (nonatomic, assign) NSInteger accuracy;
@property (nonatomic, retain) NSString *countryNameCode;
@property (nonatomic, retain) NSString *countryName;
@property (nonatomic, retain) NSString *subAdministrativeAreaName;
@property (nonatomic, retain) NSString *localityName;
@property (nonatomic, retain) NSArray *addressComponents;
@property (nonatomic, assign) float latitude;
@property (nonatomic, assign) float longitude;
@property (nonatomic, assign) float viewportSouthWestLat;
@property (nonatomic, assign) float viewportSouthWestLon;
@property (nonatomic, assign) float viewportNorthEastLat;
@property (nonatomic, assign) float viewportNorthEastLon;
@property (nonatomic, assign) float boundsSouthWestLat;
@property (nonatomic, assign) float boundsSouthWestLon;
@property (nonatomic, assign) float boundsNorthEastLat;
@property (nonatomic, assign) float boundsNorthEastLon;
@property (readonly) CLLocationCoordinate2D coordinate;
@property (readonly) MKCoordinateSpan coordinateSpan;
@property (readonly) MKCoordinateRegion coordinateRegion;

-(NSArray*)findAddressComponent:(NSString*)typeName;

@end

To make it somewhat simple to find address components I’ve added a method that will search for components for you. Using version 3 of the geocoding service you will get the country name using this code:

NSArray *countryName = [BSKmlResultPlace findAddressComponent:@"country"];
if([countryName count] > 0)
{
	NSLog(@"Country: %@", ((BSAddressComponent*)[countryName objectAtIndex:0]).longName );
}
[countryName release];

There are also properties to make the result simple to use with a MKMapView. The “coordinate” property returns a CLLocationCoordinate2D object, “coordinateSpan” calculates and returns a MKCoordinateSpan object for setting the map viewport. The “coordinateRegion” combines both coordinate and coordinateSpan returning a MKCoordinateRegion object that can be used to directly move your MKMapView to the right place.

BSAddressComponent

#import <Foundation/Foundation.h>

@interface BSAddressComponent : NSObject {
	NSString *longName;
	NSString *shortName;
	NSArray *types;
}

@property (nonatomic, retain) NSString *longName;
@property (nonatomic, retain) NSString *shortName;
@property (nonatomic, retain) NSArray *types;

This class maps against what’s returned in version 3 of the geocoding service. It’s just a container class.

 You can grab the sample code from Here