Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Jaisan mathew
5,300 Pointshow to store an array of type cllocationcoordinate2d in nsuserdefaults in swift 2.0
i want to save an array of location coordinates in nsuserdefaults.how to do that
2 Answers
Martin Wildfeuer
Courses Plus Student 11,071 PointsThis is indeed not to easy. You are hitting two limitations:
1. You cannot store an array of CLLocationCoordinate2D to UserDefaults directly
As the following excerpt of the UserDefaults describes, you cannot directly store an array [CLLocationCoordinate2D] to UserDefaults. Allowed are only combinations of [Int], [String] etc.
The NSUserDefaults class provides convenience methods for accessing
common types such as floats, doubles, integers, Booleans, and URLs.
A default object must be a property list—that is, an instance of (or for
collections, a combination of instances of): NSData, NSString, NSNumber,
NSDate, NSArray, or NSDictionary. If you want to store any other type of
object, you should typically archive it to create an instance of NSData.
For more details, see Preferences and Settings Programming Guide.
In order to store and retrieve custom objects to/from UserDefaults, you have to utilize NSKeyedArchiver and NSKeyedUnarchiver. However...
2. NSKeyedArchiver does not work for CLLocationCoordinate2D
I won't go into detail here why this does not work, however it does work for CLLocation which conforms to NSSecureCodingand thus can be archived. Therefore, one solution would be to convert [CLLocationCoordinate2D] to [CLLocation] before storing it to UserDefaults and vice-versa when retrieving them. The following example should work as expected.
import CoreLocation
// Store an array of CLLocationCoordinate2D
func storeCoordinates(_ coordinates: [CLLocationCoordinate2D]) {
let locations = coordinates.map { coordinate -> CLLocation in
return CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
}
let archived = NSKeyedArchiver.archivedData(withRootObject: locations)
UserDefaults.standard.set(archived, forKey: "coordinates")
UserDefaults.standard.synchronize()
}
// Return an array of CLLocationCoordinate2D
func loadCoordinates() -> [CLLocationCoordinate2D]? {
guard let archived = UserDefaults.standard.object(forKey: "coordinates") as? Data,
let locations = NSKeyedUnarchiver.unarchiveObject(with: archived) as? [CLLocation] else {
return nil
}
let coordinates = locations.map { location -> CLLocationCoordinate2D in
return location.coordinate
}
return coordinates
}
Please note that this will not in Playgrounds as UserDefaults are only available in sandboxed environments.
Now let's test our implementation:
let testCoordinates = [
CLLocationCoordinate2D(latitude: 0.123456789, longitude: 0.123456789),
CLLocationCoordinate2D(latitude: 1.123456789, longitude: 1.123456789),
CLLocationCoordinate2D(latitude: 2.123456789, longitude: 2.123456789)
]
storeCoordinates(testCoordinates)
let coordinates = loadCoordinates()
dump(coordinates)
Hope that helps :)
Jaisan mathew
5,300 Pointsthanks martin....:)