Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
InfiniteLoopDK committed Feb 22, 2011
0 parents commit f77739b
Show file tree
Hide file tree
Showing 16 changed files with 3,173 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Xcode noise
build
*.pbxuser
*.mode1v3
*.mode2v3

# Subversion
.svn

# OS X noise
.DS_Store

# Ignore TouchJSON in this project - no need to confuse things
TouchJSON
11 changes: 11 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

Copyright (c) 2010-2011, Infinite Loop
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of Infinite Loop nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 changes: 47 additions & 0 deletions README.mdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ILGeoNames

ILGeoNames provides Objective C wrapper classes for accessing the free geocoding services at [GeoNames.org]("http://www.geonames.org") from iOS.

Unlike the geocoding services provided by Google which have various restricting license terms, GeoNames allows you to use their data for practically any purpose as long as you give [proper credit]("http://www.geonames.org/export/").

## Setting up the sample application

In order to be able to use this sample application you need to perform a few additional steps first:

- Sign up for a free account a geonames.org
- Enter your new geonames account information in SampleAppDelegate.m
- Download TouchJSON

Each of these steps are detailed in more details below.

### Sign up for a free GeoNames account

If you do not already have an account with GeoNames, you first need to go to http://www.geonames.org/login and sign-up for a free account. Shortly after you should get an confirmation email with information on how to activate your account.

Once you have activated your account you also need to enable it to use the free web service. This is done from your GeoNames account page by simply clicking a link. Once enabled, your account is ready to be used with the various geocoding services.

### Setting up account information

Open the SampleApp.xcodeproj file and locate the file named `SampleAppDelegate.m`
Locate the following line near the top of the file and replace the account information with your own.

static NSString *kGeoNamesAccountName = @"ilgeonamessample";

### Download TouchJSON

The ILGeoNames classes makes use of TouchJSON by Jonathan Wight. In order to be able to build the sample project - and your own for that matter - you need to download a copy of the TouchJSON code from [GitHub]("http://github.com/TouchCode/TouchJSON")

Once downloaded, place the TouchJSON folder next to the SampleApp folder. Alternatively, if you already have your own fork of TouchJSON, just point the sample project to your local repository.

You should now be ready to compile and run the sample application. The application shows examples on how to use the following classes:

- ILGeoNamesLookup, the basic wrapper for accessing geonames.org
- ILGeoNamesSearchController, a search controller for online search of named locations


Feel free to add enhanchements, bug fixes, changes and provide them back to the community!

Thanks,

Claus Broch
http://www.infinite-loop.dk
57 changes: 57 additions & 0 deletions SampleApp/Classes/SampleAppDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// SampleAppDelegate.h
// SampleApp
//
// Created by Claus Broch on 21/02/11.
// Copyright 2011 Infinite Loop. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of conditions
// and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
// - Neither the name of Infinite Loop nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

#import "ILGeoNamesLookup.h"
#import "ILGeoNamesSearchController.h"

@interface SampleAppDelegate : NSObject
<UIApplicationDelegate, CLLocationManagerDelegate, ILGeoNamesLookupDelegate, ILGeoNamesSearchControllerDelegate> {
UIWindow *window;
CLLocationManager *locationManager;
ILGeoNamesLookup *geocoder;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UIViewController *controller;
@property (nonatomic, retain) IBOutlet UIButton *currentButton;
@property (nonatomic, retain) IBOutlet UIButton *searchButton;
@property (nonatomic, retain) IBOutlet UILabel *position;
@property (nonatomic, retain) IBOutlet UILabel *locationName;
@property (nonatomic, retain) IBOutlet UILabel *locationType;
@property (nonatomic, retain) IBOutlet UILabel *country;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) ILGeoNamesLookup *geocoder;

- (IBAction)currentPosition:(id)sender;
- (IBAction)searchLocation:(id)sender;

@end

259 changes: 259 additions & 0 deletions SampleApp/Classes/SampleAppDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
//
// SampleAppDelegate.m
// SampleApp
//
// Created by Claus Broch on 21/02/11.
// Copyright 2011 Infinite Loop. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of conditions
// and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
// - Neither the name of Infinite Loop nor the names of its contributors may be used to endorse or
// promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#import "SampleAppDelegate.h"

// IMPORTANT - change the following line to use your own geonames.org account
static NSString *kGeoNamesAccountName = @"ilgeonamessample";

@implementation SampleAppDelegate

@synthesize window;
@synthesize controller;
@synthesize currentButton;
@synthesize searchButton;
@synthesize position;
@synthesize locationName;
@synthesize locationType;
@synthesize country;
@synthesize locationManager;
@synthesize geocoder;

#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Override point for customization after application launch.

[self.window makeKeyAndVisible];

return YES;
}


- (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, called instead of applicationWillTerminate: when the user quits.
*/
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of 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.
See also applicationDidEnterBackground:.
*/
}

- (IBAction)currentPosition:(id)sender {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;

// Set a timeout so we don't keep searching forever
[locationManager startUpdatingLocation];
[locationManager performSelector:@selector(stopUpdatingLocation) withObject:nil afterDelay:30.0];
}

- (IBAction)searchLocation:(id)sender {
ILGeoNamesSearchController *searchController = [[ILGeoNamesSearchController alloc] init];
searchController.delegate = self;

searchController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.controller presentModalViewController:searchController animated:YES];

[searchController release];
}

#pragma mark -
#pragma mark CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 60.0)
return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0)
return;

// we have a measurement that meets our requirements, so we can stop updating the location
//
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
//
[NSObject cancelPreviousPerformRequestsWithTarget:locationManager selector:@selector(stopUpdatingLocation) object:nil];
[locationManager stopUpdatingLocation];

position.text = [NSString stringWithFormat:@"%.5f%c %.5f%c",
fabs(newLocation.coordinate.latitude), newLocation.coordinate.latitude >= 0.0 ? 'N' : 'S',
fabs(newLocation.coordinate.longitude), newLocation.coordinate.longitude >= 0.0 ? 'E' : 'W'];

// Request location information from geonames.org
self.geocoder = [[[ILGeoNamesLookup alloc] initWithUserID:kGeoNamesAccountName] autorelease];
geocoder.delegate = self;
[geocoder findNearbyPlaceNameForLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];

}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// The location "unknown" error simply means the manager is currently unable to get the location.
// We can ignore this error for the scenario of getting a single location fix, because we already have a
// timeout that will stop the location manager to save power.
if ([error code] != kCLErrorLocationUnknown) {
[locationManager stopUpdatingLocation];

// For now just display an alert
position.text = @"Unknown location";
UIAlertView *anAlert = [[UIAlertView alloc] initWithTitle:@"Error getting location" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[anAlert show];
[anAlert release];
}
}

#pragma mark -
#pragma mark ILGeoNamesLookupDelegate

- (void)geoNamesLookup:(ILGeoNamesLookup *)handler networkIsActive:(BOOL)isActive
{
// Spin the activity indicator while receiving data
[UIApplication sharedApplication].networkActivityIndicatorVisible = isActive;
}

- (void)geoNamesLookup:(ILGeoNamesLookup *)handler didFindGeoNames:(NSArray *)geoNames totalFound:(NSUInteger)total
{
BOOL gotGeocode = NO;
NSString *name;

NSLog(@"didFindGeoNames: %@", [geoNames description]);

// Grab the name of the first place
if (geoNames && [geoNames count] >= 1) {
NSDictionary *placeName = [geoNames objectAtIndex:0];
name = [placeName objectForKey:@"name"];
if(name) {
self.locationName.text = name;
self.locationType.text = [placeName objectForKey:@"fcodeName"];
self.country.text = [placeName objectForKey:@"countryName"];
gotGeocode = YES;
}
}

if(!gotGeocode) {
self.locationName.text = @"Unknown location";
self.locationType.text = @"";
self.country.text = @"";
}
}

- (void)geoNamesLookup:(ILGeoNamesLookup *)handler didFailWithError:(NSError *)error
{
// TODO error handling
NSLog(@"ILGeoNamesLookup has failed: %@", [error localizedDescription]);
self.locationName.text = @"Unknown location";
}


#pragma mark -
#pragma mark ILGeoNamesSearchControllerDelegate methods

- (NSString*)geoNamesUserIDForSearchController:(ILGeoNamesSearchController*)controller {
return kGeoNamesAccountName;
}

- (void)geoNamesSearchController:(ILGeoNamesSearchController*)controller didFinishWithResult:(NSDictionary*)result
{
NSLog(@"didFinishWithResult: %@", result);
[self.controller dismissModalViewControllerAnimated:YES];

if(result) {
double latitude = [[result objectForKey:@"lat"] doubleValue];
double longitude = [[result objectForKey:@"lng"] doubleValue];
position.text = [NSString stringWithFormat:@"%.5f%c %.5f%c",
fabs(latitude), latitude >= 0.0 ? 'N' : 'S',
fabs(longitude), longitude >= 0.0 ? 'E' : 'W'];
self.locationName.text = [result objectForKey:@"name"];
self.locationType.text = [result objectForKey:@"fcodeName"];
self.country.text = [result objectForKey:@"countryName"];
}
}


#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}


- (void)dealloc {
[window release];
[controller release];
[currentButton release];
[searchButton release];
[position release];
[locationName release];
[locationType release];
[country release];
[locationManager release];
[geocoder release];

[super dealloc];
}


@end
Loading

0 comments on commit f77739b

Please sign in to comment.