Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit 4010b1d

Browse files
author
Julian Rex
authored
[ios] Added pending completion blocks (#15122)
1 parent 5c066f8 commit 4010b1d

File tree

4 files changed

+484
-31
lines changed

4 files changed

+484
-31
lines changed

platform/ios/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
55
## master
66

77
* Fixed an issue that caused the tilt gesture to trigger too easily and conflict with pinch or pan gestures. ([#15349](https://github.com/mapbox/mapbox-gl-native/pull/15349))
8+
* Fixed a bug with annotation view positions after camera transitions. ([#15122](https://github.com/mapbox/mapbox-gl-native/pull/15122/))
89

910
## 5.3.0
1011

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
#import "MGLMapViewIntegrationTest.h"
2+
#import "MGLTestUtility.h"
3+
4+
@interface MGLMapView (MGLMapViewPendingBlockTests)
5+
@property (nonatomic) NSMutableArray *pendingCompletionBlocks;
6+
- (void)pauseRendering:(__unused NSNotification *)notification;
7+
@end
8+
9+
@interface MGLMapViewPendingBlockTests : MGLMapViewIntegrationTest
10+
@property (nonatomic, copy) void (^observation)(NSDictionary*);
11+
@property (nonatomic) BOOL completionHandlerCalled;
12+
@end
13+
14+
@implementation MGLMapViewPendingBlockTests
15+
16+
- (void)testSetCenterCoordinate {
17+
__typeof__(self) weakSelf = self;
18+
19+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
20+
__typeof__(self) strongSelf = weakSelf;
21+
22+
if (strongSelf) {
23+
[strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
24+
zoomLevel:10.0
25+
direction:0
26+
animated:NO
27+
completionHandler:completion];
28+
}
29+
else {
30+
completion();
31+
}
32+
};
33+
34+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
35+
transition:transition
36+
addToPendingCallback:nil];
37+
}
38+
39+
- (void)testSetCenterCoordinateAnimated {
40+
__typeof__(self) weakSelf = self;
41+
42+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
43+
__typeof__(self) strongSelf = weakSelf;
44+
45+
if (strongSelf) {
46+
[strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
47+
zoomLevel:10.0
48+
direction:0
49+
animated:YES
50+
completionHandler:completion];
51+
}
52+
else {
53+
completion();
54+
}
55+
};
56+
57+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
58+
transition:transition
59+
addToPendingCallback:nil];
60+
}
61+
62+
- (void)testSetVisibleCoordinateBounds {
63+
__typeof__(self) weakSelf = self;
64+
65+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
66+
__typeof__(self) strongSelf = weakSelf;
67+
68+
if (strongSelf) {
69+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
70+
[strongSelf.mapView setVisibleCoordinateBounds:unitBounds
71+
edgePadding:UIEdgeInsetsZero
72+
animated:NO
73+
completionHandler:completion];
74+
}
75+
else {
76+
completion();
77+
}
78+
};
79+
80+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
81+
transition:transition
82+
addToPendingCallback:nil];
83+
}
84+
85+
- (void)testSetVisibleCoordinateBoundsAnimated {
86+
__typeof__(self) weakSelf = self;
87+
88+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
89+
__typeof__(self) strongSelf = weakSelf;
90+
91+
if (strongSelf) {
92+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
93+
[strongSelf.mapView setVisibleCoordinateBounds:unitBounds
94+
edgePadding:UIEdgeInsetsZero
95+
animated:YES
96+
completionHandler:completion];
97+
}
98+
else {
99+
completion();
100+
}
101+
};
102+
103+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
104+
transition:transition
105+
addToPendingCallback:nil];
106+
}
107+
108+
- (void)testSetCamera {
109+
__typeof__(self) weakSelf = self;
110+
111+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
112+
__typeof__(self) strongSelf = weakSelf;
113+
114+
if (strongSelf) {
115+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
116+
MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
117+
118+
[strongSelf.mapView setCamera:camera withDuration:0.0 animationTimingFunction:nil completionHandler:completion];
119+
}
120+
else {
121+
completion();
122+
}
123+
};
124+
125+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
126+
transition:transition
127+
addToPendingCallback:nil];
128+
}
129+
130+
- (void)testSetCameraAnimated {
131+
__typeof__(self) weakSelf = self;
132+
133+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
134+
__typeof__(self) strongSelf = weakSelf;
135+
136+
if (strongSelf) {
137+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
138+
MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
139+
140+
[strongSelf.mapView setCamera:camera withDuration:0.3 animationTimingFunction:nil completionHandler:completion];
141+
}
142+
else {
143+
completion();
144+
}
145+
};
146+
147+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
148+
transition:transition
149+
addToPendingCallback:nil];
150+
}
151+
152+
// Marked as pending due to https://github.com/mapbox/mapbox-gl-native/issues/15471
153+
- (void)testFlyToCameraPENDING {
154+
__typeof__(self) weakSelf = self;
155+
156+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
157+
__typeof__(self) strongSelf = weakSelf;
158+
159+
if (strongSelf) {
160+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
161+
MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
162+
163+
[strongSelf.mapView flyToCamera:camera withDuration:0.0 completionHandler:completion];
164+
}
165+
else {
166+
completion();
167+
}
168+
};
169+
170+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
171+
transition:transition
172+
addToPendingCallback:nil];
173+
}
174+
175+
- (void)testFlyToCameraAnimated {
176+
177+
__typeof__(self) weakSelf = self;
178+
179+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
180+
__typeof__(self) strongSelf = weakSelf;
181+
182+
if (strongSelf) {
183+
MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
184+
MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
185+
186+
[strongSelf.mapView flyToCamera:camera withDuration:0.3 completionHandler:completion];
187+
}
188+
else {
189+
completion();
190+
}
191+
};
192+
193+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
194+
transition:transition
195+
addToPendingCallback:nil];
196+
}
197+
198+
199+
#pragma mark - test interrupting regular rendering
200+
201+
- (void)testSetCenterCoordinateSetHidden {
202+
203+
__typeof__(self) weakSelf = self;
204+
205+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
206+
__typeof__(self) strongSelf = weakSelf;
207+
208+
if (strongSelf) {
209+
[strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
210+
zoomLevel:10.0
211+
direction:0
212+
animated:NO
213+
completionHandler:completion];
214+
}
215+
else {
216+
completion();
217+
}
218+
};
219+
220+
dispatch_block_t addedToPending = ^{
221+
__typeof__(self) strongSelf = weakSelf;
222+
223+
MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
224+
225+
// Now hide the mapview
226+
strongSelf.mapView.hidden = YES;
227+
228+
MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
229+
};
230+
231+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
232+
transition:transition
233+
addToPendingCallback:addedToPending];
234+
}
235+
236+
- (void)testSetCenterCoordinatePauseRendering {
237+
238+
__typeof__(self) weakSelf = self;
239+
240+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
241+
__typeof__(self) strongSelf = weakSelf;
242+
243+
if (strongSelf) {
244+
[strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
245+
zoomLevel:10.0
246+
direction:0
247+
animated:NO
248+
completionHandler:completion];
249+
}
250+
else {
251+
completion();
252+
}
253+
};
254+
255+
dispatch_block_t addedToPending = ^{
256+
__typeof__(self) strongSelf = weakSelf;
257+
258+
MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
259+
260+
// Pause rendering, stopping display link
261+
[strongSelf.mapView pauseRendering:nil];
262+
263+
MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
264+
};
265+
266+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
267+
transition:transition
268+
addToPendingCallback:addedToPending];
269+
}
270+
271+
- (void)testSetCenterCoordinateRemoveFromSuperview {
272+
273+
__typeof__(self) weakSelf = self;
274+
275+
void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
276+
__typeof__(self) strongSelf = weakSelf;
277+
278+
if (strongSelf) {
279+
[strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
280+
zoomLevel:10.0
281+
direction:0
282+
animated:NO
283+
completionHandler:completion];
284+
}
285+
else {
286+
completion();
287+
}
288+
};
289+
290+
dispatch_block_t addedToPending = ^{
291+
__typeof__(self) strongSelf = weakSelf;
292+
293+
MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
294+
295+
// Remove from window, triggering validateDisplayLink
296+
[strongSelf.mapView removeFromSuperview];
297+
298+
MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
299+
};
300+
301+
[self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
302+
transition:transition
303+
addToPendingCallback:addedToPending];
304+
}
305+
306+
#pragma mark - Shared utility methods
307+
308+
- (void)internalTestCompletionBlockAddedToPendingForTestName:(NSString *)testName
309+
transition:(void (^)(dispatch_block_t))transition
310+
addToPendingCallback:(dispatch_block_t)addToPendingCallback {
311+
312+
XCTestExpectation *expectation = [self expectationWithDescription:testName];
313+
314+
__weak __typeof__(self) myself = self;
315+
316+
dispatch_block_t block = ^{
317+
myself.completionHandlerCalled = YES;
318+
[expectation fulfill];
319+
};
320+
321+
XCTAssertNotNil(transition);
322+
transition(block);
323+
324+
XCTAssert(!self.completionHandlerCalled);
325+
XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
326+
327+
__block BOOL blockAddedToPendingBlocks = NO;
328+
329+
// Observes changes to pendingCompletionBlocks (including additions)
330+
self.observation = ^(NSDictionary *change){
331+
332+
NSLog(@"change = %@ count = %lu", change, myself.mapView.pendingCompletionBlocks.count);
333+
334+
NSArray *value = change[NSKeyValueChangeNewKey];
335+
336+
MGLTestAssert(myself, [value isKindOfClass:[NSArray class]]);
337+
338+
if (value.count > 0) {
339+
MGLTestAssert(myself, [value containsObject:block]);
340+
MGLTestAssert(myself, !blockAddedToPendingBlocks);
341+
if ([myself.mapView.pendingCompletionBlocks containsObject:block]) {
342+
blockAddedToPendingBlocks = YES;
343+
344+
if (addToPendingCallback) {
345+
addToPendingCallback();
346+
}
347+
}
348+
}
349+
};
350+
351+
[self.mapView addObserver:self forKeyPath:@"pendingCompletionBlocks" options:NSKeyValueObservingOptionNew context:_cmd];
352+
353+
[self waitForExpectations:@[expectation] timeout:0.5];
354+
355+
XCTAssert(blockAddedToPendingBlocks);
356+
XCTAssert(self.completionHandlerCalled);
357+
XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
358+
359+
[self.mapView removeObserver:self forKeyPath:@"pendingCompletionBlocks" context:_cmd];
360+
}
361+
362+
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
363+
if (self.observation) {
364+
self.observation(change);
365+
}
366+
}
367+
@end

0 commit comments

Comments
 (0)