Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conform models to NSSecureCoding #68

Merged
merged 3 commits into from
Sep 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions MapboxDirections.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
DAC05F181CFC075300FA0071 /* MBRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC05F171CFC075300FA0071 /* MBRoute.swift */; };
DAC05F1A1CFC077C00FA0071 /* MBRouteLeg.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC05F191CFC077C00FA0071 /* MBRouteLeg.swift */; };
DAC05F1C1CFC1E5300FA0071 /* v5_driving_dc_polyline.json in Resources */ = {isa = PBXBuildFile; fileRef = DAC05F1B1CFC1E5300FA0071 /* v5_driving_dc_polyline.json */; };
DAEF6CAD1D8BC017006A108F /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAEF6CAC1D8BC017006A108F /* RouteStepTests.swift */; };
DAEF6CAE1D8BC017006A108F /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAEF6CAC1D8BC017006A108F /* RouteStepTests.swift */; };
DAEF6CAF1D8BC017006A108F /* RouteStepTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAEF6CAC1D8BC017006A108F /* RouteStepTests.swift */; };
DD6254541AE70C1700017857 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6254531AE70C1700017857 /* AppDelegate.swift */; };
DD6254561AE70C1700017857 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6254551AE70C1700017857 /* ViewController.swift */; };
FB737DB2C6D8CC82A6FAA82C /* Pods_MapboxDirectionsTVTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBA232D519F6F671B2EDFCAF /* Pods_MapboxDirectionsTVTests.framework */; };
Expand Down Expand Up @@ -242,6 +245,7 @@
DAC05F171CFC075300FA0071 /* MBRoute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MBRoute.swift; sourceTree = "<group>"; };
DAC05F191CFC077C00FA0071 /* MBRouteLeg.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MBRouteLeg.swift; sourceTree = "<group>"; };
DAC05F1B1CFC1E5300FA0071 /* v5_driving_dc_polyline.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = v5_driving_dc_polyline.json; sourceTree = "<group>"; };
DAEF6CAC1D8BC017006A108F /* RouteStepTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteStepTests.swift; sourceTree = SOURCE_ROOT; };
DD62544E1AE70C1700017857 /* Directions (Swift).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Directions (Swift).app"; sourceTree = BUILT_PRODUCTS_DIR; };
DD6254521AE70C1700017857 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DD6254531AE70C1700017857 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -414,6 +418,7 @@
isa = PBXGroup;
children = (
DA1A110A1D01045E009F82FA /* DirectionsTests.swift */,
DAEF6CAC1D8BC017006A108F /* RouteStepTests.swift */,
DA737EE71D0611CB005BDA16 /* V4Tests.swift */,
DA6C9DAB1CAEC72800094FBC /* V5Tests.swift */,
DA6C9DB11CAECA0E00094FBC /* Fixture.swift */,
Expand Down Expand Up @@ -1302,6 +1307,7 @@
DA737EE91D0611CB005BDA16 /* V4Tests.swift in Sources */,
DA1A10CE1D00F972009F82FA /* Fixture.swift in Sources */,
DA1A110C1D01045E009F82FA /* DirectionsTests.swift in Sources */,
DAEF6CAE1D8BC017006A108F /* RouteStepTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -1326,6 +1332,7 @@
DA737EEA1D0611CB005BDA16 /* V4Tests.swift in Sources */,
DA1A10F51D010251009F82FA /* Fixture.swift in Sources */,
DA1A110D1D01045E009F82FA /* DirectionsTests.swift in Sources */,
DAEF6CAF1D8BC017006A108F /* RouteStepTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1363,6 +1370,7 @@
DA737EE81D0611CB005BDA16 /* V4Tests.swift in Sources */,
DA6C9DB21CAECA0E00094FBC /* Fixture.swift in Sources */,
DA1A110B1D01045E009F82FA /* DirectionsTests.swift in Sources */,
DAEF6CAD1D8BC017006A108F /* RouteStepTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1431,7 +1439,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AB05E29E43D55326F7FA67B /* Pods-WatchExample.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
Expand All @@ -1456,7 +1463,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 05045275F3647340E9698D26 /* Pods-WatchExample.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
Expand Down
29 changes: 28 additions & 1 deletion MapboxDirections/MBRoute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Polyline
Typically, you do not create instances of this class directly. Instead, you receive route objects when you request directions using the `Directions.calculateDirections(options:completionHandler:)` method. However, if you use the `Directions.URLForCalculatingDirections(options:)` method instead, you can pass the results of the HTTP request into this class’s initializer.
*/
@objc(MBRoute)
public class Route: NSObject {
public class Route: NSObject, NSSecureCoding {
// MARK: Creating a Route

private init(profileIdentifier: String, legs: [RouteLeg], distance: CLLocationDistance, expectedTravelTime: NSTimeInterval, coordinates: [CLLocationCoordinate2D]?) {
Expand Down Expand Up @@ -49,6 +49,33 @@ public class Route: NSObject {
self.init(profileIdentifier: profileIdentifier, legs: legs, distance: distance, expectedTravelTime: expectedTravelTime, coordinates: coordinates)
}

public required init?(coder decoder: NSCoder) {
let coordinateDictionaries = decoder.decodeObjectForKey("coordinates") as? [[String: CLLocationDegrees]]
coordinates = coordinateDictionaries?.map { CLLocationCoordinate2D(latitude: $0["latitude"]!, longitude: $0["longitude"]!) }

legs = decoder.decodeObjectForKey("legs") as? [RouteLeg] ?? []
distance = decoder.decodeDoubleForKey("distance")
expectedTravelTime = decoder.decodeDoubleForKey("expectedTravelTime")
profileIdentifier = decoder.decodeObjectForKey("profileIdentifier") as! String
}

public static func supportsSecureCoding() -> Bool {
return true
}

public func encodeWithCoder(coder: NSCoder) {
let coordinateDictionaries = coordinates?.map { [
"latitude": $0.latitude,
"longitude": $0.longitude,
] }
coder.encodeObject(coordinateDictionaries, forKey: "coordinates")

coder.encodeObject(legs, forKey: "legs")
coder.encodeDouble(distance, forKey: "distance")
coder.encodeDouble(expectedTravelTime, forKey: "expectedTravelTime")
coder.encodeObject(profileIdentifier, forKey: "profileIdentifier")
}

// MARK: Getting the Route Geometry

/**
Expand Down
26 changes: 25 additions & 1 deletion MapboxDirections/MBRouteLeg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Polyline
You do not create instances of this class directly. Instead, you receive route leg objects as part of route objects when you request directions using the `Directions.calculateDirections(options:completionHandler:)` method.
*/
@objc(MBRouteLeg)
public class RouteLeg: NSObject {
public class RouteLeg: NSObject, NSSecureCoding {
// MARK: Getting the Leg Geometry

/**
Expand Down Expand Up @@ -84,6 +84,30 @@ public class RouteLeg: NSObject {
let steps = (json["steps"] as? [JSONDictionary] ?? []).map { RouteStep(json: $0) }
self.init(steps: steps, json: json, source: source, destination: destination, profileIdentifier: profileIdentifier)
}

public required init?(coder decoder: NSCoder) {
source = decoder.decodeObjectForKey("source") as! Waypoint
destination = decoder.decodeObjectForKey("destination") as! Waypoint
steps = decoder.decodeObjectForKey("steps") as? [RouteStep] ?? []
name = decoder.decodeObjectForKey("name") as! String
distance = decoder.decodeDoubleForKey("distance")
expectedTravelTime = decoder.decodeDoubleForKey("expectedTravelTime")
profileIdentifier = decoder.decodeObjectForKey("profileIdentifier") as! String
}

public static func supportsSecureCoding() -> Bool {
return true
}

public func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(source, forKey: "source")
coder.encodeObject(destination, forKey: "destination")
coder.encodeObject(steps, forKey: "steps")
coder.encodeObject(name, forKey: "name")
coder.encodeDouble(distance, forKey: "distance")
coder.encodeDouble(expectedTravelTime, forKey: "expectedTravelTime")
coder.encodeObject(profileIdentifier, forKey: "profileIdentifier")
}
}

// MARK: Support for Directions API v4
Expand Down
73 changes: 71 additions & 2 deletions MapboxDirections/MBRouteStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ public enum ManeuverDirection: Int, CustomStringConvertible {
You do not create instances of this class directly. Instead, you receive route step objects as part of route objects when you request directions using the `Directions.calculateDirections(options:completionHandler:)` method, setting the `includesSteps` option to `true` in the `RouteOptions` object that you pass into that method.
*/
@objc(MBRouteStep)
public class RouteStep: NSObject {
public class RouteStep: NSObject, NSSecureCoding {
// MARK: Getting the Step Geometry

/**
Expand Down Expand Up @@ -472,7 +472,7 @@ public class RouteStep: NSObject {

In some cases, the number of exits leading to a maneuver may be more useful to the user than the distance to the maneuver.
*/
public let exitIndex: NSInteger?
public let exitIndex: Int?

// MARK: Getting Details About the Approach to the Next Maneuver

Expand Down Expand Up @@ -558,6 +558,75 @@ public class RouteStep: NSObject {

self.init(finalHeading: finalHeading, maneuverType: maneuverType, maneuverDirection: maneuverDirection, maneuverLocation: maneuverLocation, name: name, coordinates: coordinates, json: json)
}

public required init?(coder decoder: NSCoder) {
let coordinateDictionaries = decoder.decodeObjectForKey("coordinates") as? [[String: CLLocationDegrees]]
coordinates = coordinateDictionaries?.map { CLLocationCoordinate2D(latitude: $0["latitude"]!, longitude: $0["longitude"]!) }

instructions = decoder.decodeObjectForKey("instructions") as! String
initialHeading = decoder.containsValueForKey("initialHeading") ? decoder.decodeDoubleForKey("initialHeading") : nil
finalHeading = decoder.containsValueForKey("finalHeading") ? decoder.decodeDoubleForKey("finalHeading") : nil

let maneuverTypeDescription = decoder.decodeObjectForKey("maneuverType") as! String
maneuverType = ManeuverType(description: maneuverTypeDescription)
let maneuverDirectionDescription = decoder.decodeObjectForKey("maneuverDirection") as! String
maneuverDirection = ManeuverDirection(description: maneuverDirectionDescription)

if let maneuverLocationDictionary = decoder.decodeObjectForKey("maneuverLocation") as? [String: CLLocationDegrees] {
maneuverLocation = CLLocationCoordinate2D(latitude: maneuverLocationDictionary["latitude"]!, longitude: maneuverLocationDictionary["longitude"]!)
} else {
maneuverLocation = kCLLocationCoordinate2DInvalid
}

exitIndex = decoder.containsValueForKey("exitIndex") ? decoder.decodeIntegerForKey("exitIndex") : nil
distance = decoder.decodeDoubleForKey("distance")
expectedTravelTime = decoder.decodeDoubleForKey("expectedTravelTime")
name = decoder.decodeObjectForKey("name") as? String

let transportTypeDescription = decoder.decodeObjectForKey("transportType") as! String
transportType = TransportType(description: transportTypeDescription)

destinations = decoder.decodeObjectForKey("destinations") as? String
}

public static func supportsSecureCoding() -> Bool {
return true
}

public func encodeWithCoder(coder: NSCoder) {
let coordinateDictionaries = coordinates?.map { [
"latitude": $0.latitude,
"longitude": $0.longitude,
] }
coder.encodeObject(coordinateDictionaries, forKey: "coordinates")

coder.encodeObject(instructions, forKey: "instructions")

if let initialHeading = initialHeading {
coder.encodeDouble(initialHeading, forKey: "initialHeading")
}
if let finalHeading = finalHeading {
coder.encodeDouble(finalHeading, forKey: "finalHeading")
}

coder.encodeObject(maneuverType?.description, forKey: "maneuverType")
coder.encodeObject(maneuverDirection?.description, forKey: "maneuverDirection")

coder.encodeObject([
"latitude": maneuverLocation.latitude,
"longitude": maneuverLocation.longitude,
], forKey: "maneuverLocation")

if let exitIndex = exitIndex {
coder.encodeInteger(exitIndex, forKey: "exitIndex")
}

coder.encodeDouble(distance, forKey: "distance")
coder.encodeDouble(expectedTravelTime, forKey: "expectedTravelTime")
coder.encodeObject(name, forKey: "name")
coder.encodeObject(transportType?.description, forKey: "transportType")
coder.encodeObject(destinations, forKey: "destinations")
}
}

// MARK: Support for Directions API v4
Expand Down
44 changes: 44 additions & 0 deletions RouteStepTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import XCTest
@testable import MapboxDirections

class RouteStepTests: XCTestCase {
func testCoding() {
let coordinates = [
CLLocationCoordinate2D(latitude: -122.220694, longitude: 37.853913),
CLLocationCoordinate2D(latitude: -122.22044, longitude: 37.854032),
CLLocationCoordinate2D(latitude: -122.220168, longitude: 37.854149),
]
let json = [
"mode": "driving",
"maneuver": [
"instruction": "Keep left at the fork onto CA 24",
"bearing_before": 55,
],
"distance": 1669.7,
"duration": 75.6,
]

let step = RouteStep(finalHeading: 59, maneuverType: .ReachFork, maneuverDirection: .Left, maneuverLocation: CLLocationCoordinate2D(latitude: 37.853913, longitude: -122.220694), name: nil, coordinates: coordinates, json: json)

let data = NSKeyedArchiver.archivedDataWithRootObject(step)
let unarchivedStep = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! RouteStep
XCTAssertNotNil(unarchivedStep)

XCTAssertEqual(unarchivedStep.coordinates?.count, step.coordinates?.count)
XCTAssertEqual(unarchivedStep.coordinates?.first?.latitude, step.coordinates?.first?.latitude)
XCTAssertEqual(unarchivedStep.coordinates?.first?.longitude, step.coordinates?.first?.longitude)
XCTAssertEqual(unarchivedStep.instructions, step.instructions)
XCTAssertEqual(unarchivedStep.initialHeading, step.initialHeading)
XCTAssertEqual(unarchivedStep.finalHeading, step.finalHeading)
XCTAssertEqual(unarchivedStep.maneuverType, step.maneuverType)
XCTAssertEqual(unarchivedStep.maneuverDirection, step.maneuverDirection)
XCTAssertEqual(unarchivedStep.maneuverLocation.latitude, step.maneuverLocation.latitude)
XCTAssertEqual(unarchivedStep.maneuverLocation.longitude, step.maneuverLocation.longitude)
XCTAssertEqual(unarchivedStep.exitIndex, step.exitIndex)
XCTAssertEqual(unarchivedStep.distance, step.distance)
XCTAssertEqual(unarchivedStep.expectedTravelTime, step.expectedTravelTime)
XCTAssertEqual(unarchivedStep.name, step.name)
XCTAssertEqual(unarchivedStep.transportType, step.transportType)
XCTAssertEqual(unarchivedStep.destinations, step.destinations)
}
}