Skip to content

Commit b81cdcf

Browse files
author
Adam Iredale
committed
Add NSCopy, NSCoding, equality and hash conformance
- Bumped Podspec to 1.0.2 for convenience - Renamed ISOcountryCode to countryCode to make working with Core Data objects sleeker - Added coding and copying routines, equality and hash routines - Added unit tests to verify above routines
1 parent a8c89b0 commit b81cdcf

File tree

6 files changed

+1275
-345
lines changed

6 files changed

+1275
-345
lines changed

LMGeocoder.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22

33
s.name = 'LMGeocoder'
4-
s.version = '1.0.1'
4+
s.version = '1.0.2'
55
s.summary = 'Simple wrapper for geocoding and reverse geocoding, using both Google Geocoding API and Apple iOS Geocoding Framework.'
66
s.homepage = 'https://github.com/lminhtm/LMGeocoder'
77
s.license = {

LMGeocoder/LMAddress.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#import <Foundation/Foundation.h>
1010
#import <CoreLocation/CoreLocation.h>
1111

12-
@interface LMAddress : NSObject
12+
@interface LMAddress : NSObject <NSCopying, NSCoding>
1313

1414
/*!
1515
* The location coordinate
@@ -54,7 +54,7 @@
5454
/*!
5555
* The ISO country code (e.g. AU)
5656
*/
57-
@property (nonatomic, copy) NSString *ISOcountryCode;
57+
@property (nonatomic, copy) NSString *countryCode;
5858

5959
/*!
6060
* The formatted address

LMGeocoder/LMAddress.m

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,29 @@ @implementation LMAddress
2020
@synthesize country;
2121
@synthesize formattedAddress;
2222
@synthesize isValid;
23-
@synthesize ISOcountryCode;
23+
@synthesize countryCode;
24+
25+
#pragma mark - CONSTANTS
26+
27+
// @Double
28+
static NSString *const LMLatitudeKey = @"latitude";
29+
static NSString *const LMLongitudeKey = @"longitude";
30+
// @BOOL
31+
static NSString *const LMIsValidKey = @"isValid";
32+
// NSString
33+
static NSString *const LMStreetNumberKey = @"streetNumber";
34+
static NSString *const LMRouteKey = @"route";
35+
static NSString *const LMLocalityKey = @"locality";
36+
static NSString *const LMSubLocalityKey = @"subLocality";
37+
static NSString *const LMAdministrativeAreaKey = @"administrativeArea";
38+
static NSString *const LMPostalCodeKey = @"postalCode";
39+
static NSString *const LMCountryKey = @"country";
40+
static NSString *const LMFormattedAddressKey = @"formattedAddress";
41+
static NSString *const LMCountryCodeKey = @"countryCode";
42+
43+
#define allStringKeys @[LMStreetNumberKey, LMRouteKey, LMLocalityKey, LMSubLocalityKey, \
44+
LMAdministrativeAreaKey, LMPostalCodeKey, LMCountryKey, \
45+
LMFormattedAddressKey, LMCountryCodeKey]
2446

2547
#pragma mark - INIT
2648

@@ -47,6 +69,83 @@ - (id)initWithLocationData:(id)locationData forServiceType:(int)serviceType
4769
return self;
4870
}
4971

72+
#pragma mark - EQUALITY
73+
74+
- (BOOL)isEqual:(id)object
75+
{
76+
BOOL equal = [super isEqual:object];
77+
if (equal)
78+
{
79+
return YES;
80+
}
81+
if ([object isKindOfClass:[self class]] == NO)
82+
{
83+
return NO;
84+
}
85+
LMAddress *other = object;
86+
// Lat/Long
87+
equal = (self.coordinate.latitude == other.coordinate.latitude);
88+
equal &= (self.coordinate.longitude == other.coordinate.longitude);
89+
// IsValid
90+
equal &= (self.isValid == other.isValid);
91+
// The rest
92+
for (NSString *key in allStringKeys)
93+
{
94+
equal &= [[self valueForKey:key] isEqual:[other valueForKey:key]];
95+
}
96+
return equal;
97+
}
98+
99+
- (NSUInteger)hash
100+
{
101+
// Should be enough to hash-table well
102+
NSUInteger hashValue = (self.isValid ? 1 : 0);
103+
hashValue += floor(self.coordinate.latitude) + floor(self.coordinate.longitude);
104+
hashValue += self.formattedAddress.hash;
105+
return hashValue;
106+
}
107+
108+
#pragma mark - NSCODING
109+
110+
- (id)initWithCoder:(NSCoder *)aDecoder
111+
{
112+
self = [self init];
113+
if (self)
114+
{
115+
// Load doubles into coordinate
116+
self.coordinate = CLLocationCoordinate2DMake([aDecoder decodeDoubleForKey:LMLatitudeKey],
117+
[aDecoder decodeDoubleForKey:LMLongitudeKey]);
118+
// Load bool
119+
self.isValid = [aDecoder decodeBoolForKey:LMIsValidKey];
120+
// Load the strings into properties by name
121+
for (NSString *key in allStringKeys)
122+
{
123+
[self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
124+
}
125+
}
126+
return self;
127+
}
128+
129+
- (void)encodeWithCoder:(NSCoder *)aCoder
130+
{
131+
// Double
132+
[aCoder encodeDouble:self.coordinate.latitude forKey:LMLatitudeKey];
133+
[aCoder encodeDouble:self.coordinate.longitude forKey:LMLongitudeKey];
134+
// Bool
135+
[aCoder encodeBool:self.isValid forKey:LMIsValidKey];
136+
// String
137+
for (NSString *key in allStringKeys)
138+
{
139+
[aCoder encodeObject:[self valueForKey:key] forKey:key];
140+
}
141+
}
142+
143+
#pragma mark - NSCOPYING
144+
145+
- (id)copyWithZone:(NSZone *)zone
146+
{
147+
return [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self]];
148+
}
50149

51150
#pragma mark - PARSING
52151

@@ -67,7 +166,7 @@ - (void)setAppleLocationData:(id)locationData
67166
self.administrativeArea = placemark.administrativeArea;
68167
self.postalCode = placemark.postalCode;
69168
self.country = placemark.country;
70-
self.ISOcountryCode = placemark.ISOcountryCode;
169+
self.countryCode = placemark.ISOcountryCode;
71170
self.formattedAddress = [lines componentsJoinedByString:@", "];
72171
}
73172
else
@@ -99,7 +198,7 @@ - (void)setGoogleLocationData:(id)locationData
99198
self.administrativeArea = [self component:@"administrative_area_level_1" inArray:addressComponents ofType:@"long_name"];
100199
self.postalCode = [self component:@"postal_code" inArray:addressComponents ofType:@"short_name"];
101200
self.country = [self component:@"country" inArray:addressComponents ofType:@"long_name"];
102-
self.ISOcountryCode = [self component:@"country" inArray:addressComponents ofType:@"short_name"];
201+
self.countryCode = [self component:@"country" inArray:addressComponents ofType:@"short_name"];
103202
self.formattedAddress = formattedAddrs;
104203
}
105204
else
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>com.lminhtm.$(PRODUCT_NAME:rfc1034identifier)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>BNDL</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleSignature</key>
20+
<string>????</string>
21+
<key>CFBundleVersion</key>
22+
<string>1</string>
23+
</dict>
24+
</plist>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//
2+
// LMGeocoder_Tests.m
3+
// LMGeocoder Tests
4+
//
5+
// Created by Adam Iredale on 15/01/2015.
6+
// Copyright (c) 2015 LMinh. All rights reserved.
7+
//
8+
9+
#import <UIKit/UIKit.h>
10+
#import <XCTest/XCTest.h>
11+
#import "LMAddress.h"
12+
13+
@interface LMGeocoder_Tests : XCTestCase
14+
15+
@end
16+
17+
@implementation LMGeocoder_Tests
18+
19+
#pragma mark - SetUp & TearDown
20+
21+
- (void)setUp {
22+
[super setUp];
23+
// Put setup code here. This method is called before the invocation of each test method in the class.
24+
}
25+
26+
- (void)tearDown {
27+
// Put teardown code here. This method is called after the invocation of each test method in the class.
28+
[super tearDown];
29+
}
30+
31+
#pragma mark - Helpers
32+
33+
- (LMAddress *)createTestAddress
34+
{
35+
// It's a block past Maple on the East end of town...
36+
LMAddress *address = nil;
37+
@autoreleasepool
38+
{
39+
address = [[LMAddress alloc] init];
40+
address.coordinate = CLLocationCoordinate2DMake(34.151607, -118.160948);
41+
address.streetNumber = @"1640";
42+
address.route = @"Riverside Drive";
43+
address.locality = @"Hill Valley";
44+
address.subLocality = @"Hill Valley East";
45+
address.administrativeArea = @"California";
46+
address.postalCode = @"91103";
47+
address.country = @"United States";
48+
address.countryCode = @"US";
49+
address.formattedAddress = @"1640 Riverside Drive, Hill Valley CA 91103, United States";
50+
address.isValid = YES;
51+
}
52+
return address;
53+
}
54+
55+
#pragma mark - Tests
56+
57+
- (void)testValidCopyIsEqualToOriginal
58+
{
59+
LMAddress *original = [self createTestAddress];
60+
original.isValid = YES;
61+
XCTAssertEqualObjects(original, [original copy]);
62+
}
63+
64+
- (void)testInvalidCopyIsEqualToOriginal
65+
{
66+
LMAddress *original = [self createTestAddress];
67+
original.isValid = NO;
68+
XCTAssertEqualObjects(original, [original copy]);
69+
}
70+
71+
- (void)testAlteredCopyIsNotEqualToOriginal
72+
{
73+
LMAddress *original = [self createTestAddress];
74+
LMAddress *alteredCopy = [original copy];
75+
alteredCopy.route = @"John F. Kennedy Drive";
76+
XCTAssertNotEqualObjects(original, alteredCopy);
77+
}
78+
79+
- (void)testCopyPerformance
80+
{
81+
LMAddress *original = [self createTestAddress];
82+
[self measureBlock:^{
83+
[original copy];
84+
}];
85+
}
86+
87+
@end

0 commit comments

Comments
 (0)