-
Notifications
You must be signed in to change notification settings - Fork 90
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
Offline Tile downloader #303
Conversation
} | ||
|
||
@objc(MBOfflineDirections) | ||
public class OfflineDirections: NSObject, URLSessionDownloadDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably fold this into Directions
if we mention offline
in the signature and/or documentation.
@1ec5 what’s your take on this?
|
||
return session.downloadTask(with: url) { [weak self] (tempLocalUrl, response, error) in | ||
if let tempLocalUrl = tempLocalUrl, error == nil { | ||
// TODO: Move file from temporary location to a provided location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To do...
66ee09f
to
f4733d8
Compare
} | ||
|
||
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) { | ||
// TODO: resume download when range headers are supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add support for this in advance of the feature availability on the server?
Fetches the available versions. | ||
*/ | ||
@discardableResult | ||
func availableOfflineVersions(completionHandler: @escaping OfflineVersionsHandler) -> URLSessionDataTask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this method returns a task rather than the offline versions themselves, rename it to getAvailableOfflineVersions(completionHandler:)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get
is only used when getting values indirectly (such as UIColor.getRed(_:&green:&blue:&alpha:&)
) in Cocoa but I get the point. How about fetch/list/find?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fetch is fine.
MapboxDirections/MBBoundingBox.swift
Outdated
A bounding box represents a geographic region. | ||
*/ | ||
@objc(MBBoundingBox) | ||
public class BoundingBox: NSObject, Codable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The map SDK has a similar struct named MGLCoordinateBounds
, and MapboxGeocoder.swift has a CLRegion subclass named RectangularRegion. It would be great if we could make this class a struct, for value semantics; otherwise, a subclass of CLRegion would at least make some of the capabilities more discoverable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, yeah, it's unfortunate that MapboxDirections doesn't depend on those. Would be nice to share a core set of data types, similar to what gl-native is doing.
I went back and forth with CLRegion but didn't find it adding any value. CoordinateBounds makes sense for consistency. How about {MB}/CoordinateBounds
?
Swift struct wouldn't bridge to Obj-C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turf-swift has a BoundingBox but we are partially striving for turf-js/GeoJSON terminology there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GeoJSON terminology makes more sense for a library that’s very much about manipulating GeoJSON, such as Turf, but unless we have this library depend on Turf – not necessarily a bad idea – I kind of like CoordinateBounds for consistency with the map SDK. I agree that CLRegion isn’t adding much in this case; MapboxGeocoder.swift has that to be more similar to MapKit’s and Core Location’s geocoders.
Swift struct wouldn't bridge to Obj-C.
A C struct does bridge to Swift, so implement it in an Objective-C header. path
could be a C function refined by a Swift-only extension method on this struct.
MapboxDirections/MBDirections.swift
Outdated
internal var offlineProgressHandler: OfflineDownloaderProgressHandler? | ||
|
||
/// The handler that reports the completion of an offline tile pack | ||
internal var offlineCompletionHandler: OfflineDownloaderCompletionHandler? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s a bit awkward that these properties are here in the main class definition because of an extension’s conformance to OfflineDirectionsProtocol.
More significantly, these properties make Directions stateful. Directions originally was stateful, going so far as to store the URLSessionTask for the API request, similar to MapKit’s MKDirections. But that made it impossible for a single Directions object to process multiple requests simultaneously, and it also meant that the object had to be held strongly for the duration of the request. #47 moved Directions to a stateless singleton model that has provided a good deal of flexibility to this library. If we’re going to return to the old model, Directions would need to encapsulate the URLSessionTask objects and provide a method for canceling the request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Reverted back to a stateless version of Directions with an optional URLSession you can pass in to modify configurations and receive delegate callbacks such as progress updates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MapboxDirections.swift takes the approach of exposing the request URL publicly, so you can hook the library into any networking library, not just URLSession but also AFNetworking etc.
} | ||
|
||
@objc(MBVersion) | ||
public class Version: NSObject, Codable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There would be somewhat less boilerplate if we made Version a struct instead. It would have to be defined in Objective-C in order to support both languages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. The version should be represented as a String according to the api team.
func availableVersionsURL() -> URL { | ||
|
||
let url = apiEndpoint.appendingPathComponent("route-tiles/v1").appendingPathComponent("versions") | ||
var components = URLComponents(string: url.absoluteString) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
||
static var dateFormatter: DateFormatter = { | ||
let formatter = DateFormatter() | ||
formatter.dateFormat = "yyyy-MM-dd" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the off-chance that there needs to be two versions on the same day, would the API ever assign a more precise timestamp?
9277b0f
to
ac1b11e
Compare
ac1b11e
to
99228a4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly stylistic nits remaining, but I do think we should try to use a C struct for the bounding box type, because reference semantics are unexpected for that concept (except for CLRegion).
|
||
extension Directions: OfflineDirectionsProtocol { | ||
|
||
func availableVersionsURL() -> URL { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turn this method into a computed variable if possible.
return components!.url! | ||
} | ||
|
||
func tilesURL(for boundingBox: BoundingBox, version: OfflineVersion) -> URL { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider replacing for
with a more descriptive label, such as covering
, or rename the method to url(forTilesIn:version:)
.
|
||
@discardableResult | ||
@objc | ||
public func downloadTiles(for boundingBox: BoundingBox, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
downloadTiles(in:…
.
@objc | ||
public func downloadTiles(for boundingBox: BoundingBox, | ||
version: OfflineVersion, | ||
session: URLSession? = URLSession.shared, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even more flexible would be to expose url(forTilesIn:version:)
publicly, so that developers can use the URL with either a custom URLSession or another networking library such as AFNetworking.
b5b9806
to
08d69de
Compare
08d69de
to
fc491a4
Compare
Introduced Offline Tile downloader
Added two new public methods:
Directions.fetchAvailableVersions(completionHandler:)
Directions.downloadTiles(in:version:completionHandler:)
Unit test download progress(Add Pause/Resume and progress updates to Directions.downloadTiles #306)Unit test resume download(Add Pause/Resume and progress updates to Directions.downloadTiles #306)cc @1ec5 @JThramer @akitchen