How to search MKMapView with UISearchBar? - iphone

I have an application that needs to have a similar search feature like the Apple "Maps" application (included with iPhone, iPod Touch and iPad).
The feature in question should not be a hard thing to do, but I'm really clueless about how to input a Street Address in the search bar, and then obtaining coordinates for that address or something that can help me to actually move the map and center in that place.
I mean, what do I have to query, does Apple provide an "address searching API method" ? or I need to use the google maps API directly ?
I would love to hear how should it be done.

Ok, to answer my own question:
As was mentioned before, the best thing to do is to use the Google Maps API,
it supports a lot of formats but for several reasons I chose to go with JSON.
So here are the steps to perform a JSON query to Google Maps and obtain the coordinate of the query. Note that not all the correct validations are done, this is only a Proof of concept.
1) Download a JSON framework/library for the iPhone, there are several, I chose to go with this one, it's very good and seems an active project, plus several comercial applications seem to be using it. So add it to your project ( instructions here ).
2) To query Google Maps for an address we need to build a request URL like this:
http://maps.google.com/maps/geo?q=Paris+France
This url, will return a JSON object for the query "Paris+France".
3) Code:
//Method to handle the UISearchBar "Search",
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
//Perform the JSON query.
[self searchCoordinatesForAddress:[searchBar text]];
//Hide the keyboard.
[searchBar resignFirstResponder];
}
After we handle the UISearchBar search, we must make the request to Google Maps:
- (void) searchCoordinatesForAddress:(NSString *)inAddress
{
//Build the string to Query Google Maps.
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#?output=json",inAddress];
//Replace Spaces with a '+' character.
[urlString setString:[urlString stringByReplacingOccurrencesOfString:#" " withString:#"+"]];
//Create NSURL string from a formate URL string.
NSURL *url = [NSURL URLWithString:urlString];
//Setup and start an async download.
//Note that we should test for reachability!.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
We must of course then handle the response of the GoogleMaps server ( Note: a lot of validations missing)
//It's called when the results of [[NSURLConnection alloc] initWithRequest:request delegate:self] come back.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//The string received from google's servers
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//JSON Framework magic to obtain a dictionary from the jsonString.
NSDictionary *results = [jsonString JSONValue];
//Now we need to obtain our coordinates
NSArray *placemark = [results objectForKey:#"Placemark"];
NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:#"Point.coordinates"];
//I put my coordinates in my array.
double longitude = [[coordinates objectAtIndex:0] doubleValue];
double latitude = [[coordinates objectAtIndex:1] doubleValue];
//Debug.
//NSLog(#"Latitude - Longitude: %f %f", latitude, longitude);
//I zoom my map to the area in question.
[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
[jsonString release];
}
Finally the function to zoom my map, which should by now be a trivial thing.
- (void) zoomMapAndCenterAtLatitude:(double) latitude andLongitude:(double) longitude
{
MKCoordinateRegion region;
region.center.latitude = latitude;
region.center.longitude = longitude;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta = .005;
span.longitudeDelta = .005;
region.span = span;
//Move the map and zoom
[mapView setRegion:region animated:YES];
}
Hope this helps someone because the JSON part was a real pain to figure out, the library is not very well documented in my opinion, still it's very good.
EDIT:
Modified one method name to "searchCoordinatesForAddress:" because of #Leo question. I have to say that this method is good as a proof of concept but if you plan to download big JSON files , you will have to append to a NSMutableData object to hold all the query to the google server. ( remember that HTTP queries come by pieces . )

This link helps you if you search a region.
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#?output=json",inAddress];
If you want to search a street this is the corect link
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=json",inAddress];
Notice that the 2nd ? should be &.

Swift version, adapted for iOS 9:
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(addressString) { (placemarks, error) in
if let center = (placemarks?.first?.region as? CLCircularRegion)?.center {
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpanMake(0.02, 0.02))
self.mapView.setRegion(region, animated: true)
}
}
based on user1466453's answer.

If anyone else is having the same issue, heres the link:
https://github.com/stig/json-framework/
scroll down to Project renamed to SBJson
Also, here is the code for getting all the data before your app uses it. Note the delegate method 'did receive data' as it appends the mutable data object with the downloaded data.
I JUST USED MR GANDOS searchCoodinatesMETHOD AS IT IS AS IT WORKS WELL
- (void) searchCoordinatesForAddress:(NSString *)inAddress
{
//Build the string to Query Google Maps.
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=false",inAddress];
//Replace Spaces with a '+' character.
[urlString setString:[urlString stringByReplacingOccurrencesOfString:#" " withString:#"+"]];
//Create NSURL string from a formate URL string.
NSURL *url = [NSURL URLWithString:urlString];
//Setup and start an async download.
//Note that we should test for reachability!.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
// STEP ONE
// THIS ONE IS IMPORTANT AS IT CREATES THE MUTABLE DATA OBJECT AS SOON AS A RESPONSE IS RECEIVED
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
if (receivedGeoData)
{
[receivedGeoData release];
receivedGeoData = nil;
receivedGeoData = [[NSMutableData alloc] init];
}
else
{
receivedGeoData = [[NSMutableData alloc] init];
}
}
/// STEP TWO
// THIS ONE IS IMPORTANT AS IT APPENDS THE DATA OBJECT WITH THE DATA
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedGeoData appendData:data];
}
// STEP THREE......
// NOW THAT YOU HAVE ALL THE DATA MAKE USE OF IT
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *jsonResult = [[NSString alloc] initWithData:receivedGeoData encoding:NSUTF8StringEncoding];
NSError *theError = NULL;
dictionary = [NSMutableDictionary dictionaryWithJSONString:jsonResult error:&theError];
NSLog(#"%#",dictionary);
int numberOfSites = [[dictionary objectForKey:#"results"] count];
NSLog(#"count is %d ",numberOfSites);
}
-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
// Handle the error properly
}

You can use Google's API service to get lat/long coords from a textual search string. Be sure to pass the user's current location so the results are relevant. Read the answers to this question: Search and display business locations on MKMapView

Related

Search nearby in iOS Maps

I am trying to build a simple application using MapKit that will automatically search for a specific place when the app launches and drop pin(s) on the map at the locations(s). I am seeing all sorts of ways to load locations (lat/lon, etc), but nothing that lets me search for a specific business name, restaurant name, etc.
I am expecting to work with Apple Maps. However, if Google Maps would be a better solve than so be it.
Any help would be appreciated. Thanks
iOS >= 6.1 provides MKLocalSearch, MKLocalSearchRequest to search for natural language points of interest. Sample
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = regionToSearchIn;
request.naturalLanguageQuery = #"restaurants"; // or business name
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
// do something with the results / error
}];
i know its late but hope this helps!
[super viewDidLoad];
[self.searchDisplayController setDelegate:self];
[self.ibSearchBar setDelegate:self];
self.ibMapView.delegate=self;
// Zoom the map to current location.
[self.ibMapView setShowsUserLocation:YES];
[self.ibMapView setUserInteractionEnabled:YES];
[self.ibMapView setUserTrackingMode:MKUserTrackingModeFollow];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate=self;
[locationManager startUpdatingLocation];
[self.ibMapView setRegion:MKCoordinateRegionMake(locationManager.location.coordinate, MKCoordinateSpanMake(0.2, 0.2))];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.ibMapView.region;
request.naturalLanguageQuery = #"restaurant";
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
results = response;
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else
for (MKMapItem *item in response.mapItems)
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
[_matchingItems addObject:item];
MKPointAnnotation *annotation =
[[MKPointAnnotation alloc]init];
annotation.coordinate = item.placemark.coordinate;
annotation.title = item.name;
[self.ibMapView addAnnotation:annotation];
}
}];
}
Make the following steps to display nearest places.
Using google API find the Nearest Places Google Places API
The google API provide LAt and Long and address Informations.
Then Store the LAt and Long Values to Array then USing this lat and long values you can display Annotations in Apple map (iOS 6+) and Google Map (iOS 5).

iPhone - Google Directions API Response Problems

I am using the Google Directions iOS API. I am getting the data using JSON instead of XML. But I am using AFNetworking to simplify this for me. AFNetworking is available at github. Right now, I am able to display an overlay route from one location to another on an MKMapView. Here is my code:
// AFNETWORKING ==========================================================
AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location.coordinate.latitude, location.coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location2.coordinate.latitude, location2.coordinate.longitude] forKey:#"destination"];
[parameters setObject:#"false" forKey:#"sensor"];
[parameters setObject:#"driving" forKey:#"mode"];
[parameters setObject:#"metric" forKey: #"units"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:responseObject];
} else {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
// ROUTE SETUP AND RESPONSE RECIEVED METHOD ==========================================================
- (void)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
NSLog(#"Status: %#", [response objectForKey: #"status"]);
NSLog(#"Legs: %#", [routePath objectForKey: #"legs[]"]);
_path = [self decodePolyLine:overviewPolyline];
NSInteger numberOfSteps = _path.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
}
This is the main code to get the route functioning. And it works well! But now what I want to do is get direction list and complete duration and summary. So I took a deep look at Google Directions API Documentation and it tells me to use its different dictionaries and arrays and objects. But I have had no luck. I get a status of OK. When I log the count of the routes array, its only one object. Then the MOST important, legs[] array is NULL.
NSLog(#"Legs is: %#", [routePath objectForKey: #"legs[]"]);
Output:
Legs is (null)
Legs[] includes everything important like the direction list and duration. Summary is not NULL, it gives the name of one of the streets that the route bypasses. I dont know how that is a summary. Might be because there is only one object in the routes array. waypoint_order and warnings[] are NULL too. bounds and of course overview_polyline are valid, thats how I got the route working.
So whats the problem here? Why are so many of the objects Google Directions API provides NULL when I need them?
Thanks!
Alright, the problem was that the response for directions was taking too long. I expected the legs[] response to instantly deliver along with the overview_polyline. So I just had to wait till the response came in, this gives me an opportunity to insert a buffer UI.

Efficiency of Google Geocoding with Dispatch Queue - How to Improve - iPhone

I have a Google Map view in my app which is populated with pins via geocoding. I am using the below code to create a dispatch queue which then queries Google for the longitude and latitude for each place in my app.
The problem is that although the below code works to some extent, it seems to miss a large percentage of items on its first run through. These items are added to the array "failedLoad" as per the code below.
At the moment I am running a second method to add the places in failedLoad which is called whenever the ViewDidLoad method is called. However this is a poor solution as even after this second method is run there are still items in failedLoad and also I would prefer for all the pins to load without relying on ViewDidLoad (which is only called if the user taps on a pin, then returns from the detail view screen which is presented).
Can anyone suggest a good way of improving this process ?
Thank you
-(void)displayPlaces {
for (PlaceObject *info in mapLocations) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^
{
// GET ANNOTATION INFOS
NSString * addressOne = info.addressOne;
NSString * name = info.name;
NSString * postCode = info.postCode;
NSString * addressTwo = [addressOne stringByAppendingString:#",London,"];
NSString * address = [addressTwo stringByAppendingString:postCode];
NSError * error;
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&error];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
double latitude = 0.0;
double longitude = 0.0;
if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:#"200"]) {
latitude = [[listItems objectAtIndex:2] doubleValue];
longitude = [[listItems objectAtIndex:3] doubleValue];
}
else {
NSLog(#"Error %#",name);
[failedLoad addObject : info];
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude;
coordinate.longitude = longitude;
MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease];
dispatch_sync(dispatch_get_main_queue(), ^{
// ADD ANNOTATION
[mapViewLink addAnnotation:annotation];
});
});
}
GCD is great but you should never use threading techniques if the SDK already offers an asynchronous API for this. In your case, never use stringWithContentsOfURL: as it is a synchronous & blocking code (which is probably why you switch to using GCD to make it in the background) while NSURLConnection has an asynchronous API. always use this asynchrounous API instead when you need to do any network request.
This is better for many reasons:
one being that it's an API already designed for this in the SDK (even if you will probably need to create a class like MyGeocoder that sends the request, handle the response, parse it, and return the value in an asynchronous way)
but the most significant reason to prefer the asynchronous API (over using the synchronous stringWithContentsOfURL + GCD) is that NSURLConnection is integrated with the NSRunLoop and schedules the retrieval of the socket data on the runloop, avoiding to create a lot of useless threads for that (and threads are evil if you use it where it is not strictly needed).
And finally, as NSURLConnection lifecycle is handled by the RunLoop itself, the delegate methods are already called on the main thread.
GCD is always better than using NSThreads directly, but using Runloop scheduling for things that are already made for in the SDK, especially NSURLConnections is always better both for performance (avoid thread scheduling issues), multithreading issues and much more.
[EDIT]
For example if you don't want to implement the class yourself, you can use my sample OHURLLoader class and use it this way:
NSString* urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURL* url = [NSURL URLWithString:urlString];
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
NSString* locationString = loader.receivedString;
NSArray *listItems = [locationString componentsSeparatedByString:#","];
... etc ...
// this callback / block is executed on the main thread so no problem to write this here
[mapViewLink addAnnotation:annotation];
} errorHandler:^(NSError *error) {
NSLog(#"Error while downloading %#: %#",url,error);
}];

Xcode iOS 4.2.1 -> Give Map View the address to show the pin? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Forward Geocode Example using CLGeocoder
I have a plist full of names and their adrresses. I want my iOS app to show on a map view a pin with the address of the person he has selected. Can I import the address to map view and get a pin? And how?? Thank you.
Use the CLGeocoder class to convert addresses into lat/long coordinates:
Forward Geocode Example using CLGeocoder
The more accurate address you have, the better the result should be so with exact addresses you should get very accurate points.
Another option is to use Google's geocoding web service, simply pass the address string to this function and you will get an CLLocationCoordinate2D which contains a latitude & longitude.
Right now it grabs the location at the 0th index, which is the closest matching result. Log out the result to see the JSON response from Google.
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=true&address=%#", esc_addr];
CLLocationCoordinate2D center;
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result)
{
//NSLog(#"LOC RESULT: %#", result);
NSError *e;
NSDictionary *resultDict = [NSJSONSerialization JSONObjectWithData: [result dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &e];
NSArray *resultsArray = [resultDict objectForKey:#"results"];
if(resultsArray.count > 0)
{
resultDict = [[resultsArray objectAtIndex:0] objectForKey:#"geometry"];
resultDict = [resultDict objectForKey:#"location"];
center.latitude = [[resultDict objectForKey:#"lat"] floatValue];
center.longitude = [[resultDict objectForKey:#"lng"] floatValue];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Results Found" message:#"No locations were found using, please try again." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
//goes through each result
/*for(NSDictionary *dict in resultsArray)
{
resultDict = [dict objectForKey:#"geometry"];
resultDict = [resultDict objectForKey:#"location"];
}*/
}
return center;
}
This is whats known as Forward Geocoding, and there is no built in API to do this for you. You need to use an external service, which one you use really depends on your app.
I have used Google's service for this. http://code.google.com/apis/maps/documentation/geocoding/
It is a very simple API, but has restrictions based on your app's license. I know there are a couple other services for this, but I'll leave that as an exercise to you.

Moving through JSON data in iPhone app

I'm afraid I'm a newbie to objective-c programming, and I am having a problem that I have spent all day trying to figure out and I cannot, so I am humbly asking you guys if anyone can help.
I am trying to read the details from a JSON page online (for instance a local services directory) and have installed the JSON library into Xcode and it seems to work fine. I'm developing for the iPhone by the way, and have the latest versions all installed.
The problem is, what with me being a newb and all, I seem unable to retrieve all the information I need from the JSON file.
the JSON data I am testing with is this:
"testlocal_response" = {
header = {
query = {
business = newsagent;
location = brighton;
page = 1;
"per_page" = 1;
"query_path" = "business/index";
};
status = ok;
};
records = (
{
address1 = "749 Rwlqsmuwgj Jcyv";
address2 = "<null>";
"average_rating" = 0;
"business_id" = 4361366;
"business_keywords" = "<null>";
"business_name" = "Gloucester Newsagents";
"data_provider_id" = "<null>";
"display_details" = "<null>";
"distance_in_miles" = "0.08";
fax = "<null>";
gridx = "169026.3";
gridy = "643455.7";
"image_url" = "<null>";
latitude = "50.82718";
"logo_path" = Deprecated;
longitude = "-0.13963";
phone = 97204438976;
postcode = "IY1 6CC";
"reviews_count" = 0;
"short_description" = "<null>";
"touch_url" = "http://www.test.com/business/list/bid/4361366";
town = BRIGHTON;
url = "<null>";
}
);
};
}
Now, in my code ViewController.m page, in the 'connectionDidFinishLoading' area I have added:
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
// make sure JSON has all been pulled in
NSLog(#"This is from the JSON page:\n");
NSLog(responseString);
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
// using either of these seems to make no difference?
NSDictionary *touchDirect = [json objectWithString:responseString error:&error];
//NSArray *touchDirect = [json objectWithString:responseString error:&error];
[responseString release];
if (touchDirect == nil)
label.text = [NSString stringWithFormat:#"JSON parsing failed: %#", [error localizedDescription]];
else {
NSMutableString *text = [NSMutableString stringWithString:#"Test directory details:\n"];
[text appendFormat:#"%#\n", [[[[touchDirect objectForKey:#"testlocal_response"] objectForKey:#"header"] objectForKey:#"query"] objectForKey:#"business"]];
label.text = text;
Testing this I get the value for the business ('newsagent') returned, or location ('brighton') which is the correct. My problem is, I cannot go further into the JSON. I don't know how to pull out the result for the actual 'records' which, in the test example there is only one of but can be more divided using brackets '(' and ')'.
As soon as I try to access the data in these record areas (such as 'address1' or 'latitude' or 'postcode') it fails and tells me 'unrecognized selector sent to instance'
PLEASE can anyone tell me what I'm doing wrong?! I've tried so many different things and just cant get any further! I've read all sorts of different things online but nothing seems to help me.
Any replies deeply appreciated. I posted up a question on iPhone SDK too but havent had a useful response yet.
many thanks,
-Robsa
Have you validated your JSON?
It's not clear how you are trying to access the objects that you say are erroring. The specific line(s) you are having trouble with would be helpful.
It's usually easier to set a pointer to the dictionary you are going to be accessing for readability..
NSDictionary *records = [[objectForKey:#"testlocal_response"] objectForKey#"records"];
then...
NSString *businessName = [records objectForKey:#"business_name"];
float latitude = [[records objectForKey:#"latitude"] floatValue];
Well, I finally sorted it out! I put the records in an NSString, which I could then access using objectAtIndex.
Here is the main Viewcontroller.m code for it:
- (void)viewDidLoad {
[super viewDidLoad];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"*URL TO JSON DATA HERE*"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSMutableArray *touchDirect = [json objectWithString:responseString error:&error];
NSString *touchRecord = [[touchDirect objectForKey:#"touchlocal_response"] objectForKey:#"records"];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
label.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
//Retrieves the JSON header Data, returning info such as 'status' [which should return 'ok']
NSMutableArray *touchDirect = [json objectWithString:responseString error:&error];
//Puts the records returned into a string called touchRecord
NSString *touchRecord = [[touchDirect objectForKey:#"touchlocal_response"] objectForKey:#"records"];
[responseString release];
// test results
[text appendFormat:#" Address: %#\n", [[touchRecord objectAtIndex:0] objectForKey:#"address1"]];
[text appendFormat:#" Phone: %#\n", [[touchRecord objectAtIndex:0] objectForKey:#"phone"]];
[text appendFormat:#" Address Data record 2: %#\n", [[touchRecord objectAtIndex:1] objectForKey:#"address1"]];
[text appendFormat:#" Phone Data record 2: %#\n", [[touchRecord objectAtIndex:1] objectForKey:#"phone"]];
This now seems to work fine. I also have a if..else if statement to catch errors now. Does this code look Ok?
Thanks for the tip, Nick - I was just trying to get the output right before tidying the code up. I am using an NSMutableArray to put my JSON into initially, is this OK? What is the benefit of putting it into an NSDictionary?
regards,
Robsa