From 2bb6163f647aa86ec38f11041e52643887de2fb1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 19 Feb 2014 18:38:05 -0800 Subject: [PATCH 01/13] moves from NSURLConnection to NSURLSession on iOS --- ios/MBXViewController.mm | 27 +++++++++++---------------- ios/llmr-app.gyp | 2 +- llmr.gyp | 2 +- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 8d734459cd0..06f60b3144b 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -377,7 +377,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecogni MBXMapView *mapView; CADisplayLink *displayLink; -NSOperationQueue *queue; namespace llmr { @@ -390,20 +389,13 @@ void restart(void *) void request_http(std::string url, std::function background_function, std::function foreground_callback) { - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@1 forKey:@"count"]]; - - if (!queue) - queue = [NSOperationQueue new]; - - NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@(url.c_str())]]; - - [NSURLConnection sendAsynchronousRequest:urlRequest - queue:queue - completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@(-1) forKey:@"count"]]; + Response res; - if (error == nil) + if ( ! error) { res.code = [(NSHTTPURLResponse *)response statusCode]; res.body = { (const char *)[data bytes], [data length] }; @@ -413,12 +405,15 @@ void request_http(std::string url, std::function background_fun dispatch_async(dispatch_get_main_queue(), ^(void) { - foreground_callback(); - }); + foreground_callback(); - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@(-1) forKey:@"count"]]; - [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; + }); }]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@1 forKey:@"count"]]; + + [task resume]; } double time() diff --git a/ios/llmr-app.gyp b/ios/llmr-app.gyp index b9cec1ca638..d290397263b 100644 --- a/ios/llmr-app.gyp +++ b/ios/llmr-app.gyp @@ -37,7 +37,7 @@ 'INFOPLIST_FILE': 'Info.plist', 'CLANG_CXX_LIBRARY': 'libc++', 'CLANG_CXX_LANGUAGE_STANDARD':'c++11', - 'IPHONEOS_DEPLOYMENT_TARGET':'6.0', + 'IPHONEOS_DEPLOYMENT_TARGET':'7.0', 'TARGETED_DEVICE_FAMILY': '1,2', 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', 'CLANG_ENABLE_OBJC_ARC': 'YES' diff --git a/llmr.gyp b/llmr.gyp index bd94746fa1d..836a4d098a0 100644 --- a/llmr.gyp +++ b/llmr.gyp @@ -140,7 +140,7 @@ 'ARCHS': [ "armv7", "armv7s", "arm64", "i386" ], 'TARGETED_DEVICE_FAMILY': '1,2', 'CODE_SIGN_IDENTITY': 'iPhone Developer', - 'IPHONEOS_DEPLOYMENT_TARGET': '5.0', + 'IPHONEOS_DEPLOYMENT_TARGET': '7.0', 'PUBLIC_HEADERS_FOLDER_PATH': 'include', 'GCC_INPUT_FILETYPE':'sourcecode.cpp.cpp', 'OTHER_CPLUSPLUSFLAGS':[ From fded15dab041ae0bd9e6dd25c7cb9e1947f19eb0 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 19 Feb 2014 17:23:54 -0800 Subject: [PATCH 02/13] add tile-specific platform HTTP request --- include/llmr/platform/platform.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 41144fa632f..68cbb33efe7 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -12,6 +12,8 @@ namespace llmr { class Tile; +typedef std::shared_ptr tile_ptr; + namespace platform { // Restarts painting. This could for example trigger the event loop of the controlling application. @@ -25,6 +27,9 @@ struct Response { // Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. void request_http(std::string url, std::function background_function, std::function foreground_callback); +// Makes a tile-specific HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Access to the tile object is provided via a shared pointer. +void request_http_tile(std::string tile_template_url, tile_ptr tile_object, std::function background_function, std::function foreground_callback); + // Returns a relative timestamp in seconds. This value must be monotonic. double time(); From d94b8bbcec6466634c05d69ae07f5ebbae19e8cf Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 19 Feb 2014 23:09:48 -0800 Subject: [PATCH 03/13] make use of new tile-specific fetches to allow cancellation --- ios/MBXViewController.mm | 61 +++++++++++++++++++++++++++++++++++----- src/map/tile.cpp | 2 +- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 06f60b3144b..f79a853b0bd 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -16,6 +16,7 @@ #include #include +#include NSString *const MBXNeedsRenderNotification = @"MBXNeedsRenderNotification"; NSString *const MBXUpdateActivityNotification = @"MBXUpdateActivityNotification"; @@ -23,7 +24,6 @@ @interface MBXViewController () @property (nonatomic) EAGLContext *context; -@property (nonatomic) NSUInteger activityCount; @property (nonatomic) CGPoint center; @property (nonatomic) CGFloat scale; @property (nonatomic) CGFloat angle; @@ -153,11 +153,14 @@ - (void)updateRender:(NSNotification *)notification - (void)updateNetworkActivity:(NSNotification *)notification { - NSInteger input = [[notification userInfo][@"count"] integerValue]; - - self.activityCount += input; + [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) + { + for (NSURLSessionDownloadTask *task in downloadTasks) + if (task.taskDescription) + return [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(self.activityCount > 0)]; + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + }]; } - (void)updateRender @@ -391,7 +394,48 @@ void request_http(std::string url, std::function background_fun { NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@(-1) forKey:@"count"]]; + Response res; + + if ( ! error) + { + res.code = [(NSHTTPURLResponse *)response statusCode]; + res.body = { (const char *)[data bytes], [data length] }; + } + + background_function(res); + + dispatch_async(dispatch_get_main_queue(), ^(void) + { + foreground_callback(); + }); + }]; + + [task resume]; + } + + void request_http_tile(std::string url, tile_ptr tile_object, std::function background_function, std::function foreground_callback) + { + NSString *latestZoom = [@(tile_object->id.z) stringValue]; + + [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) + { + for (NSURLSessionDownloadTask *task in downloadTasks) + { + if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom]) + { + [task cancel]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; + } + } + }]; + + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; + + if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) + return; Response res; @@ -409,9 +453,12 @@ void request_http(std::string url, std::function background_fun [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; }); + }]; - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil userInfo:[NSDictionary dictionaryWithObject:@1 forKey:@"count"]]; + task.taskDescription = [@(tile_object->id.z) stringValue]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; [task resume]; } diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 902c2c03bb6..9e9dc5aac2f 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -72,7 +72,7 @@ void Tile::request() { // Note: Somehow this feels slower than the change to request_http() std::shared_ptr tile = shared_from_this(); - platform::request_http(url, [=](platform::Response& res) { + platform::request_http_tile(url, tile, [=](platform::Response& res) { if (res.code == 200) { tile->data.swap(res.body); tile->parse(); From 536e0343c955180da850628cbe6282bfaf162321 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 19 Feb 2014 17:33:22 -0800 Subject: [PATCH 04/13] only post needs render notification on successful tiles --- ios/MBXViewController.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index f79a853b0bd..ba1b2978d0e 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -450,10 +450,10 @@ void request_http_tile(std::string url, tile_ptr tile_object, std::functionid.z) stringValue]; From eac69ae30c4777f2593fe3d46c10e9fc1449211c Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 19 Feb 2014 23:13:20 -0800 Subject: [PATCH 05/13] move to cancellable tile-specific fetches on OS X --- macosx/llmr-app.gyp | 2 +- macosx/main.mm | 69 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/macosx/llmr-app.gyp b/macosx/llmr-app.gyp index 9b589c72304..b206e8d76a6 100644 --- a/macosx/llmr-app.gyp +++ b/macosx/llmr-app.gyp @@ -41,7 +41,7 @@ 'INFOPLIST_FILE': 'Info.plist', 'CLANG_CXX_LIBRARY': 'libc++', 'CLANG_CXX_LANGUAGE_STANDARD':'c++11', - 'MACOSX_DEPLOYMENT_TARGET':'10.8', + 'MACOSX_DEPLOYMENT_TARGET':'10.9', 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', 'CLANG_ENABLE_OBJC_ARC': 'YES' }, diff --git a/macosx/main.mm b/macosx/main.mm index 7c2f0cc1ecf..49fa13ea431 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -3,6 +3,7 @@ #import #import #include +#include #include "settings.hpp" #include @@ -229,34 +230,68 @@ void restart(void *) { mapView->dirty = true; } -void request_http(std::string url, std::function background_function, std::function foreground_callback) { - if (!queue) { - queue = [NSOperationQueue new]; - } +void request_http(std::string url, std::function background_function, std::function foreground_callback) +{ + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + Response res; + + if ( ! error) + { + res.code = [(NSHTTPURLResponse *)response statusCode]; + res.body = { (const char *)[data bytes], [data length] }; + } + + background_function(res); + + dispatch_async(dispatch_get_main_queue(), ^(void) + { + foreground_callback(); + }); + }]; - NSMutableURLRequest *urlRequest = [NSMutableURLRequest - requestWithURL:[NSURL - URLWithString:@(url.c_str())]]; + [task resume]; +} + +void request_http_tile(std::string url, tile_ptr tile_object, std::function background_function, std::function foreground_callback) +{ + NSString *latestZoom = [@(tile_object->id.z) stringValue]; + + [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) + { + for (NSURLSessionDownloadTask *task in downloadTasks) + if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom]) + [task cancel]; + }]; + + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) + return; - [NSURLConnection - sendAsynchronousRequest:urlRequest - queue:[NSOperationQueue mainQueue] - completionHandler: ^(NSURLResponse * response, NSData * data, NSError * error) { Response res; - if (error == nil) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - res.code = [httpResponse statusCode]; + + if ( ! error) + { + res.code = [(NSHTTPURLResponse *)response statusCode]; res.body = { (const char *)[data bytes], [data length] }; } background_function(res); - dispatch_async(dispatch_get_main_queue(), ^(void) { + + dispatch_async(dispatch_get_main_queue(), ^(void) + { foreground_callback(); }); - [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; + + if ( ! error) + [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; }]; -} + task.taskDescription = [@(tile_object->id.z) stringValue]; + + [task resume]; +} double time() { return glfwGetTime(); From cfbde8242977c7a1b691261dcd3611915de5714b Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 20 Feb 2014 00:16:54 -0800 Subject: [PATCH 06/13] only post activity notification once after cancels --- ios/MBXViewController.mm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index ba1b2978d0e..93161314a87 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -420,14 +420,10 @@ void request_http_tile(std::string url, tile_ptr tile_object, std::function Date: Fri, 21 Feb 2014 17:10:06 -0800 Subject: [PATCH 07/13] properly set 10.9 deploy again --- llmr.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llmr.gyp b/llmr.gyp index 028d11763d7..c28dcd5514e 100644 --- a/llmr.gyp +++ b/llmr.gyp @@ -51,7 +51,7 @@ 'xcode_settings': { 'SDKROOT': 'macosx', 'SUPPORTED_PLATFORMS':['macosx'], - 'MACOSX_DEPLOYMENT_TARGET':'10.8', + 'MACOSX_DEPLOYMENT_TARGET':'10.9', 'PUBLIC_HEADERS_FOLDER_PATH': 'include', 'OTHER_CPLUSPLUSFLAGS':[ '<@(png_cflags)' From 78ab66b06cfd2b4e80355dbfd760da7ec356f7a9 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 15:26:12 -0800 Subject: [PATCH 08/13] rename tile state ready -> parsed --- include/llmr/map/tile.hpp | 2 +- src/map/map.cpp | 8 ++++---- src/map/tile.cpp | 2 +- src/renderer/painter.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index dd107eb7b7f..297da8b7171 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -43,7 +43,7 @@ class Tile : public std::enable_shared_from_this, enum state { initial, loading, - ready, + parsed, obsolete }; diff --git a/src/map/map.cpp b/src/map/map.cpp index d09b505f479..4aecfceba16 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -278,7 +278,7 @@ bool Map::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::f auto ids = Tile::children(id, z + 1); for (const Tile::ID& child_id : ids) { const Tile::Ptr& tile = hasTile(child_id); - if (tile && tile->state == Tile::ready) { + if (tile && tile->state == Tile::parsed) { assert(tile); retain.emplace_front(tile->id); } else { @@ -305,7 +305,7 @@ bool Map::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::for for (int32_t z = id.z - 1; z >= minCoveringZoom; --z) { const Tile::ID parent_id = Tile::parent(id, z); const Tile::Ptr tile = hasTile(parent_id); - if (tile && tile->state == Tile::ready) { + if (tile && tile->state == Tile::parsed) { assert(tile); retain.emplace_front(tile->id); return true; @@ -361,7 +361,7 @@ bool Map::updateTiles() { Tile::Ptr tile = addTile(id); assert(tile); - if (tile->state != Tile::ready) { + if (tile->state != Tile::parsed) { // The tile we require is not yet loaded. Try to find a parent or // child tile that we already have. @@ -416,7 +416,7 @@ bool Map::render() { for (Tile::Ptr& tile : tiles) { assert(tile); - if (tile->state == Tile::ready) { + if (tile->state == Tile::parsed) { painter.changeMatrix(tile->id); painter.render(tile); } diff --git a/src/map/tile.cpp b/src/map/tile.cpp index e30fc203b13..cd8f686b1c8 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -115,7 +115,7 @@ bool Tile::parse() { if (state == obsolete) { return false; } else { - state = ready; + state = parsed; } return true; diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index d1ab263891a..bad921045fb 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -132,7 +132,7 @@ void Painter::clear() { } void Painter::render(const Tile::Ptr& tile) { - if (tile->state != Tile::ready) { + if (tile->state != Tile::parsed) { return; } From 0406a8229903c880dc37fe5a6654fd49f9e3d4f5 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 15:34:32 -0800 Subject: [PATCH 09/13] add tile state 'loaded' --- include/llmr/map/tile.hpp | 1 + src/map/tile.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 297da8b7171..74bc1d472b4 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -43,6 +43,7 @@ class Tile : public std::enable_shared_from_this, enum state { initial, loading, + loaded, parsed, obsolete }; diff --git a/src/map/tile.cpp b/src/map/tile.cpp index cd8f686b1c8..d0fd329d232 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -76,7 +76,8 @@ void Tile::request() { // Note: Somehow this feels slower than the change to request_http() std::shared_ptr tile = shared_from_this(); platform::request_http_tile(url, tile, [=](platform::Response& res) { - if (res.code == 200) { + if (res.code == 200 && tile->state != obsolete) { + tile->state = Tile::loaded; tile->data.swap(res.body); tile->parse(); } else { @@ -99,7 +100,7 @@ void Tile::cancel() { bool Tile::parse() { // std::lock_guard lock(mtx); - if (state == obsolete) { + if (state != loaded) { return false; } From 55b28aaf6507569c9d1bb87279c8382f043e8b11 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 16:33:06 -0800 Subject: [PATCH 10/13] allow for cancellable request, track in tiles, and cancel when obsolete --- include/llmr/map/tile.hpp | 3 +- include/llmr/platform/platform.hpp | 13 +++++-- ios/MBXViewController.mm | 61 ++++++++---------------------- macosx/main.mm | 45 ++++++---------------- src/map/tile.cpp | 5 ++- 5 files changed, 41 insertions(+), 86 deletions(-) diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 74bc1d472b4..d738c99bb74 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -93,8 +94,8 @@ class Tile : public std::enable_shared_from_this, private: // Source data std::string data; - const Style& style; + platform::Request req; }; } diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 18936a4b1c2..3dfbc01665c 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -19,16 +19,21 @@ namespace platform { // Restarts painting. This could for example trigger the event loop of the controlling application. void restart(); +struct Request { + int16_t identifier = -1; + std::string original_url; +}; + struct Response { int16_t code = -1; std::string body; }; -// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. -void request_http(std::string url, std::function background_function, std::function foreground_callback); +// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Returns a cancellable request. +Request request_http(std::string url, std::function background_function, std::function foreground_callback); -// Makes a tile-specific HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Access to the tile object is provided via a shared pointer. -void request_http_tile(std::string tile_template_url, tile_ptr tile_object, std::function background_function, std::function foreground_callback); +// Cancels an HTTP request. +void cancel_request_http(Request request); // Returns a relative timestamp in seconds. This value must be monotonic. double time(); diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 11446f01f0f..26f9adf6c87 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -155,11 +155,7 @@ - (void)updateNetworkActivity:(NSNotification *)notification { [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { - for (NSURLSessionDownloadTask *task in downloadTasks) - if (task.taskDescription) - return [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:([downloadTasks count] > 0)]; }]; } @@ -404,10 +400,12 @@ void restart() [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; } - void request_http(std::string url, std::function background_function, std::function foreground_callback) + Request request_http(std::string url, std::function background_function, std::function foreground_callback) { NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; + Response res; if ( ! error) @@ -425,52 +423,25 @@ void request_http(std::string url, std::function background_fun }]; [task resume]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; + + Request req; + + req.identifier = task.taskIdentifier; + req.original_url = url; + + return req; } - void request_http_tile(std::string url, tile_ptr tile_object, std::function background_function, std::function foreground_callback) + void cancel_request_http(Request request) { - NSString *latestZoom = [@(tile_object->id.z) stringValue]; - [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { for (NSURLSessionDownloadTask *task in downloadTasks) - if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom]) - [task cancel]; - - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; + if (task.taskIdentifier == request.identifier) + return [task cancel]; }]; - - NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; - - if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) - return; - - Response res; - - if ( ! error) - { - res.code = [(NSHTTPURLResponse *)response statusCode]; - res.body = { (const char *)[data bytes], [data length] }; - } - - background_function(res); - - dispatch_async(dispatch_get_main_queue(), ^(void) - { - foreground_callback(); - }); - - if ( ! error) - [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; - }]; - - task.taskDescription = [@(tile_object->id.z) stringValue]; - - [[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil]; - - [task resume]; } double time() diff --git a/macosx/main.mm b/macosx/main.mm index 1a37419c5fe..dc65b75606c 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -240,7 +240,7 @@ void restart() { [[NSApplication sharedApplication] postEvent: [NSEvent eventWithCGEvent:event] atStart:NO]; } -void request_http(std::string url, std::function background_function, std::function foreground_callback) +Request request_http(std::string url, std::function background_function, std::function foreground_callback) { NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { @@ -261,46 +261,23 @@ void request_http(std::string url, std::function background_fun }]; [task resume]; + + Request req; + + req.identifier = task.taskIdentifier; + req.original_url = url; + + return req; } -void request_http_tile(std::string url, tile_ptr tile_object, std::function background_function, std::function foreground_callback) +void cancel_request_http(Request request) { - NSString *latestZoom = [@(tile_object->id.z) stringValue]; - [[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { for (NSURLSessionDownloadTask *task in downloadTasks) - if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom]) - [task cancel]; - }]; - - NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) - return; - - Response res; - - if ( ! error) - { - res.code = [(NSHTTPURLResponse *)response statusCode]; - res.body = { (const char *)[data bytes], [data length] }; - } - - background_function(res); - - dispatch_async(dispatch_get_main_queue(), ^(void) - { - foreground_callback(); - }); - - if ( ! error) - [[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil]; + if (task.taskIdentifier == request.identifier) + return [task cancel]; }]; - - task.taskDescription = [@(tile_object->id.z) stringValue]; - - [task resume]; } double time() { diff --git a/src/map/tile.cpp b/src/map/tile.cpp index d0fd329d232..67d648f8c05 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -75,7 +74,7 @@ void Tile::request() { // Note: Somehow this feels slower than the change to request_http() std::shared_ptr tile = shared_from_this(); - platform::request_http_tile(url, tile, [=](platform::Response& res) { + platform::Request request = platform::request_http(url, [=](platform::Response& res) { if (res.code == 200 && tile->state != obsolete) { tile->state = Tile::loaded; tile->data.swap(res.body); @@ -86,12 +85,14 @@ void Tile::request() { }, []() { platform::restart(); }); + req = request; } void Tile::cancel() { // TODO: thread safety if (state != obsolete) { state = obsolete; + platform::cancel_request_http(req); } else { assert((!"logic error? multiple cancelleations")); } From 8b0709a62cfad87fe0f5797e8f0b18e54e076361 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 16:37:48 -0800 Subject: [PATCH 11/13] clean up response casts --- ios/MBXViewController.mm | 2 +- macosx/main.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 26f9adf6c87..b702934954e 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -408,7 +408,7 @@ Request request_http(std::string url, std::function background_ Response res; - if ( ! error) + if ( ! error && [response isKindOfClass:[NSHTTPURLResponse class]]) { res.code = [(NSHTTPURLResponse *)response statusCode]; res.body = { (const char *)[data bytes], [data length] }; diff --git a/macosx/main.mm b/macosx/main.mm index dc65b75606c..973db9a861e 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -246,7 +246,7 @@ Request request_http(std::string url, std::function background_ { Response res; - if ( ! error) + if ( ! error && [response isKindOfClass:[NSHTTPURLResponse class]]) { res.code = [(NSHTTPURLResponse *)response statusCode]; res.body = { (const char *)[data bytes], [data length] }; From 0afc5f69672325dab372f3b24d6a742491032df0 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 16:42:14 -0800 Subject: [PATCH 12/13] remove now-unnecessary tile references in platform --- include/llmr/platform/platform.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 3dfbc01665c..ef137c20635 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -10,10 +10,6 @@ namespace llmr { -class Tile; - -typedef std::shared_ptr tile_ptr; - namespace platform { // Restarts painting. This could for example trigger the event loop of the controlling application. From 0782cfc5be92ebc79711f6f9756db303026030e3 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 25 Feb 2014 17:15:51 -0800 Subject: [PATCH 13/13] only log tile errors if not obsolete --- src/map/tile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 67d648f8c05..6d88050a79f 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -79,7 +79,7 @@ void Tile::request() { tile->state = Tile::loaded; tile->data.swap(res.body); tile->parse(); - } else { + } else if (tile->state != obsolete) { fprintf(stderr, "tile loading failed\n"); } }, []() {