diff --git a/CHANGELOG.md b/CHANGELOG.md index 37251a466..51c040fb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to the Mapbox Directions SDK for iOS +## master + +* Added `DirectionsResult.fetchStartDate` and `DirectionsResult.requestEndDate` properties. ([#335](https://github.com/mapbox/MapboxDirections.swift/pull/335)) + ## v0.26.1 * `Waypoint`s and `Tracepoint`s can now be compared for object equality. ([#331](https://github.com/mapbox/MapboxDirections.swift/pull/331)) diff --git a/MapboxDirections/MBDirections.swift b/MapboxDirections/MBDirections.swift index bfd19231f..ff40a0611 100644 --- a/MapboxDirections/MBDirections.swift +++ b/MapboxDirections/MBDirections.swift @@ -137,9 +137,9 @@ open class Directions: NSObject { // MARK: Getting Directions /** - Begins asynchronously calculating the route or routes using the given options and delivers the results to a closure. + Begins asynchronously calculating routes using the given options and delivers the results to a closure. - This method retrieves the routes asynchronously over a network connection. If a connection error or server error occurs, details about the error are passed into the given completion handler in lieu of the routes. + This method retrieves the routes asynchronously from the [Mapbox Directions API](https://www.mapbox.com/api-documentation/navigation/#directions) over a network connection. If a connection error or server error occurs, details about the error are passed into the given completion handler in lieu of the routes. Routes may be displayed atop a [Mapbox map](https://www.mapbox.com/maps/). They may be cached but may not be stored permanently. To use the results in other contexts or store them permanently, [upgrade to a Mapbox enterprise plan](https://www.mapbox.com/directions/#pricing). @@ -149,15 +149,12 @@ open class Directions: NSObject { */ @objc(calculateDirectionsWithOptions:completionHandler:) @discardableResult open func calculate(_ options: RouteOptions, completionHandler: @escaping RouteCompletionHandler) -> URLSessionDataTask { + let fetchStartDate = Date() let url = self.url(forCalculating: options) let task = dataTask(with: url, completionHandler: { (json) in let response = options.response(from: json) if let routes = response.1 { - for route in routes { - route.accessToken = self.accessToken - route.apiEndpoint = self.apiEndpoint - route.routeIdentifier = json["uuid"] as? String - } + self.postprocess(routes, fetchStartDate: fetchStartDate, uuid: json["uuid"] as? String) } completionHandler(response.0, response.1, nil) }) { (error) in @@ -168,25 +165,25 @@ open class Directions: NSObject { } /** - Begins asynchronously calculating a match using the given options and delivers the results to a closure. + Begins asynchronously calculating matches using the given options and delivers the results to a closure. + This method retrieves the matches asynchronously from the [Mapbox Map Matching API](https://docs.mapbox.com/api/navigation/#map-matching) over a network connection. If a connection error or server error occurs, details about the error are passed into the given completion handler in lieu of the routes. + + To get `Route`s based on these matches, use the `calculateRoutes(matching:completionHandler:)` method instead. - - parameter options: A `MatchOptions` object specifying the requirements for the resulting match. - - parameter completionHandler: The closure (block) to call with the resulting routes. This closure is executed on the application’s main thread. - - returns: The data task used to perform the HTTP request. If, while waiting for the completion handler to execute, you no longer want the resulting routes, cancel this task. + - parameter options: A `MatchOptions` object specifying the requirements for the resulting matches. + - parameter completionHandler: The closure (block) to call with the resulting matches. This closure is executed on the application’s main thread. + - returns: The data task used to perform the HTTP request. If, while waiting for the completion handler to execute, you no longer want the resulting matches, cancel this task. */ @objc(calculateMatchesWithOptions:completionHandler:) @discardableResult open func calculate(_ options: MatchOptions, completionHandler: @escaping MatchCompletionHandler) -> URLSessionDataTask { + let fetchStartDate = Date() let url = self.url(forCalculating: options) let data = options.encodedParam.data(using: .utf8) let task = dataTask(with: url, data: data, completionHandler: { (json) in let response = options.response(from: json) if let matches = response { - for match in matches { - match.accessToken = self.accessToken - match.apiEndpoint = self.apiEndpoint - match.routeIdentifier = json["uuid"] as? String - } + self.postprocess(matches, fetchStartDate: fetchStartDate, uuid: json["uuid"] as? String) } completionHandler(response, nil) }) { (error) in @@ -196,18 +193,26 @@ open class Directions: NSObject { return task } + /** + Begins asynchronously calculating routes that match the given options and delivers the results to a closure. + + This method retrieves the routes asynchronously from the [Mapbox Map Matching API](https://docs.mapbox.com/api/navigation/#map-matching) over a network connection. If a connection error or server error occurs, details about the error are passed into the given completion handler in lieu of the routes. + + To get the `Match`es that these routes are based on, use the `calculate(_:completionHandler:)` method instead. + + - parameter options: A `MatchOptions` object specifying the requirements for the resulting match. + - parameter completionHandler: The closure (block) to call with the resulting routes. This closure is executed on the application’s main thread. + - returns: The data task used to perform the HTTP request. If, while waiting for the completion handler to execute, you no longer want the resulting routes, cancel this task. + */ @objc(calculateRoutesMatchingOptions:completionHandler:) @discardableResult open func calculateRoutes(matching options: MatchOptions, completionHandler: @escaping RouteCompletionHandler) -> URLSessionDataTask { + let fetchStartDate = Date() let url = self.url(forCalculating: options) let data = options.encodedParam.data(using: .utf8) let task = dataTask(with: url, data: data, completionHandler: { (json) in let response = options.response(containingRoutesFrom: json) if let routes = response.1 { - for route in routes { - route.accessToken = self.accessToken - route.apiEndpoint = self.apiEndpoint - route.routeIdentifier = json["uuid"] as? String - } + self.postprocess(routes, fetchStartDate: fetchStartDate, uuid: json["uuid"] as? String) } completionHandler(response.0, response.1, nil) }) { (error) in @@ -328,4 +333,18 @@ open class Directions: NSObject { } return NSError(domain: error?.domain ?? MBDirectionsErrorDomain, code: error?.code ?? -1, userInfo: userInfo) } + + /** + Adds request- or response-specific information to each result in a response. + */ + func postprocess(_ results: [DirectionsResult], fetchStartDate: Date, uuid: String?) { + let responseEndDate = Date() + for result in results { + result.accessToken = self.accessToken + result.apiEndpoint = self.apiEndpoint + result.routeIdentifier = uuid + result.fetchStartDate = fetchStartDate + result.responseEndDate = responseEndDate + } + } } diff --git a/MapboxDirections/MBDirectionsResult.swift b/MapboxDirections/MBDirectionsResult.swift index 505caf341..ba0ebf6f9 100644 --- a/MapboxDirections/MBDirectionsResult.swift +++ b/MapboxDirections/MBDirectionsResult.swift @@ -181,4 +181,22 @@ open class DirectionsResult: NSObject, NSSecureCoding { This locale is specific to Mapbox Voice API. If `nil` is returned, the instruction should be spoken with an alternative speech synthesizer. */ @objc open var speechLocale: Locale? + + /** + The time immediately before a `Directions` object fetched this result. + + If you manually start fetching a task returned by `Directions.url(forCalculating:)`, this property is set to `nil`; use the `URLSessionTaskTransactionMetrics.fetchStartDate` property instead. This property may also be set to `nil` if you create this result from a JSON object or encoded object. + + This property does not persist after encoding and decoding. + */ + @objc open var fetchStartDate: Date? + + /** + The time immediately before a `Directions` object received the last byte of this result. + + If you manually start fetching a task returned by `Directions.url(forCalculating:)`, this property is set to `nil`; use the `URLSessionTaskTransactionMetrics.responseEndDate` property instead. This property may also be set to `nil` if you create this result from a JSON object or encoded object. + + This property does not persist after encoding and decoding. + */ + @objc open var responseEndDate: Date? }