diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index b6cde57db65..0e13b98b6fc 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -108,6 +108,11 @@ - (void)startWithCompletionHandler:(MGLMapSnapshotCompletionHandler)completion - (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion { + if (!mbgl::Scheduler::GetCurrent()) { + [NSException raise:NSInvalidArgumentException + format:@"startWithQueue:completionHandler: should be called from the main thread"]; + } + if ([self isLoading]) { [NSException raise:NSInternalInconsistencyException format:@"Already started this snapshotter."]; diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h index e4a1e828785..6fb03b7b834 100644 --- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h +++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h @@ -4,6 +4,9 @@ #define MGLTestFailWithSelf(myself, ...) \ _XCTPrimitiveFail(myself, __VA_ARGS__) +#define MGLTestAssert(myself, expression, ...) \ + _XCTPrimitiveAssertTrue(myself, expression, @#expression, __VA_ARGS__) + #define MGLTestAssertNil(myself, expression, ...) \ _XCTPrimitiveAssertNil(myself, expression, @#expression, __VA_ARGS__) diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m index d7d013d6e5c..a1a63e40a66 100644 --- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m +++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m @@ -88,14 +88,17 @@ - (void)testAllocatingSnapshotOnBackgroundQueue { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); - dispatch_async(dispatch_get_main_queue(), ^{ - [expectation fulfill]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_group_leave(group); }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); snapshotter = nil; + + dispatch_sync(dispatch_get_main_queue(), ^{ + [expectation fulfill]; + }); }); [self waitForExpectations:@[expectation] timeout:2.0]; @@ -107,11 +110,11 @@ - (void)testMultipleSnapshottersFromBackgroundQueue { } // Crashes with only 1 snapshot - NSUInteger numSnapshots = 1; CGSize size = self.mapView.bounds.size; + CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - expectation.expectedFulfillmentCount = numSnapshots; + expectation.expectedFulfillmentCount = 1; expectation.assertForOverFulfill = YES; __weak __typeof__(self) weakself = self; @@ -119,53 +122,57 @@ - (void)testMultipleSnapshottersFromBackgroundQueue { dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, QOS_MIN_RELATIVE_PRIORITY); // also for concurrent dispatch_queue_t backgroundQueue = dispatch_queue_create(__PRETTY_FUNCTION__, attr); - // Crashes with dispatch_apply too - // dispatch_apply(numSnapshots, backgroundQueue, ^(size_t run) { - // ... let's try a dispatch_async - for (size_t run = 0; run < numSnapshots; run++) { + // Use dispatch_group to keep the backgroundQueue block around (and + // so also the MGLMapSnapshotter + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); - // Use dispatch_group to keep the backgroundQueue block around (and - // so also the MGLMapSnapshotter - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); - dispatch_async(backgroundQueue, ^{ + dispatch_async(backgroundQueue, ^{ - float ratio = (float)run/(float)numSnapshots; - float latlon = (ratio*30.0) + ((1-ratio)*40.0); - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(latlon, latlon); + MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); + XCTAssertNotNil(snapshotter); - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); + MGLMapSnapshotCompletionHandler completion = ^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { + // This should be the main queue + __typeof__(self) strongself = weakself; - // This should be the main queue - __typeof__(self) strongself = weakself; + MGLTestAssertNotNil(strongself, strongself); - MGLTestAssertNotNil(strongself, strongself); + MGLTestAssertNotNil(strongself, snapshot); + MGLTestAssertNotNil(strongself, snapshot.image); + MGLTestAssertNil(strongself, error, @"Snapshot should not error with: %@", error); - MGLTestAssertNotNil(strongself, snapshot); - MGLTestAssertNotNil(strongself, snapshot.image); - MGLTestAssertNil(strongself, error, @"Snapshot should not error with: %@", error); + // Change this back to XCTAttachmentLifetimeDeleteOnSuccess when we're sure this + // test is passing. + XCTAttachment *attachment = [XCTAttachment attachmentWithImage:snapshot.image]; + attachment.lifetime = XCTAttachmentLifetimeKeepAlways; + [strongself addAttachment:attachment]; - // Change this back to XCTAttachmentLifetimeDeleteOnSuccess when we're sure this - // test is passing. - XCTAttachment *attachment = [XCTAttachment attachmentWithImage:snapshot.image]; - attachment.lifetime = XCTAttachmentLifetimeKeepAlways; - [strongself addAttachment:attachment]; - [expectation fulfill]; + dispatch_group_leave(group); + }; + + // untested + @try { + [snapshotter startWithCompletionHandler:completion]; + MGLTestFailWithSelf(weakself); + } + @catch (NSException *exception) { + MGLTestAssert(weakself, exception.name == NSInvalidArgumentException); + dispatch_group_leave(group); + } - dispatch_group_leave(group); - }]; + // Wait for the snapshot to complete + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - // Wait for the snapshot to complete - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + snapshotter = nil; - snapshotter = nil; + dispatch_sync(dispatch_get_main_queue(), ^{ + [expectation fulfill]; }); - } // end for loop + }); [self waitForExpectations:@[expectation] timeout:10.0]; }