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

Commit

Permalink
[ios] Added "pending" completion blocks - to ensure that (for example…
Browse files Browse the repository at this point in the history
…) annotation views are in the position they are expected to be at the end of an animation.
  • Loading branch information
Julian Rex committed Jul 15, 2019
1 parent cdd47c0 commit 89853dd
Showing 1 changed file with 110 additions and 30 deletions.
140 changes: 110 additions & 30 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ @interface MGLMapView () <UIGestureRecognizerDelegate,
@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@property (nonatomic, readonly) BOOL enablePresentsWithTransaction;
@property (nonatomic) UIImage *lastSnapshotImage;
@property (nonatomic) NSMutableArray *pendingCompletionBlocks;

/// Experimental rendering performance measurement.
@property (nonatomic) BOOL experimental_enableFrameRateMeasurement;
Expand Down Expand Up @@ -612,6 +613,11 @@ - (void)commonInit
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];

// Pending completion blocks are called *after* annotation views have been updated
// in updateFromDisplayLink.
_pendingCompletionBlocks = [NSMutableArray array];


// As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `pauseRendering:` in response to it, as doing
// so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225
Expand Down Expand Up @@ -1033,6 +1039,33 @@ - (CGPoint)contentCenter
return CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame));
}

#pragma mark - Pending completion blocks

- (void)processPendingBlocks
{
NSArray *blocks = self.pendingCompletionBlocks;
self.pendingCompletionBlocks = [NSMutableArray array];

for (dispatch_block_t block in blocks)
{
block();
}
}

- (BOOL)addPendingBlock:(dispatch_block_t)block
{
// Only add a block if the display link (that calls processPendingBlocks) is
// running, otherwise fall back to calling immediately.
BOOL addBlock = (_displayLink && !_displayLink.isPaused);

if (addBlock)
{
[self.pendingCompletionBlocks addObject:block];
}

return addBlock;
}

#pragma mark - Life Cycle -

- (void)updateFromDisplayLink:(CADisplayLink *)displayLink
Expand All @@ -1057,7 +1090,7 @@ - (void)updateFromDisplayLink:(CADisplayLink *)displayLink
return;
}

if (_needsDisplayRefresh)
if (_needsDisplayRefresh || (self.pendingCompletionBlocks.count > 0))
{
_needsDisplayRefresh = NO;

Expand All @@ -1066,6 +1099,13 @@ - (void)updateFromDisplayLink:(CADisplayLink *)displayLink
[self updateAnnotationViews];
[self updateCalloutView];

// Call any pending completion blocks. This is primarily to ensure
// that annotations are in the expected position after core rendering
// and map update.
//
// TODO: Consider using this same mechanism for delegate callbacks.
[self processPendingBlocks];

_mbglView->display();
}

Expand Down Expand Up @@ -1132,6 +1172,7 @@ - (void)validateDisplayLink
{
[_displayLink invalidate];
_displayLink = nil;
[self processPendingBlocks];
}
}

Expand Down Expand Up @@ -1415,6 +1456,7 @@ - (void)pauseRendering:(__unused NSNotification *)notification
[MGLMapboxEvents flush];

_displayLink.paused = YES;
[self processPendingBlocks];

if ( ! self.glSnapshotView)
{
Expand Down Expand Up @@ -1467,6 +1509,11 @@ - (void)setHidden:(BOOL)hidden
{
super.hidden = hidden;
_displayLink.paused = hidden;

if (hidden)
{
[self processPendingBlocks];
}
}

- (void)tintColorDidChange
Expand Down Expand Up @@ -3188,26 +3235,35 @@ - (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate edgePaddin
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}

dispatch_block_t pendingCompletion;

if (completion)
{
animationOptions.transitionFinishFn = [completion]() {
__weak __typeof__(self) weakSelf = self;

pendingCompletion = ^{
if (![weakSelf addPendingBlock:completion])
{
completion();
}
};

animationOptions.transitionFinishFn = [pendingCompletion]() {
// Must run asynchronously after the transition is completely over.
// Otherwise, a call to -setCenterCoordinate: within the completion
// handler would reenter the completion handler’s caller.
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});

dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}

MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
if (completion)
if (pendingCompletion)
{
[self animateWithDelay:duration animations:^{
completion();
}];
[self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
Expand Down Expand Up @@ -3374,12 +3430,22 @@ - (void)_setVisibleCoordinates:(const CLLocationCoordinate2D *)coordinates count
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}

dispatch_block_t pendingCompletion;

if (completion)
{
animationOptions.transitionFinishFn = [completion]() {
dispatch_async(dispatch_get_main_queue(), ^{
__weak __typeof__(self) weakSelf = self;

pendingCompletion = ^{
if (![weakSelf addPendingBlock:completion])
{
completion();
});
}
};

animationOptions.transitionFinishFn = [pendingCompletion]() {
dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}

Expand All @@ -3389,11 +3455,9 @@ - (void)_setVisibleCoordinates:(const CLLocationCoordinate2D *)coordinates count
MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera])
{
if (completion)
if (pendingCompletion)
{
[self animateWithDelay:duration animations:^{
completion();
}];
[self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
Expand Down Expand Up @@ -3534,22 +3598,30 @@ - (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration a
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}

dispatch_block_t pendingCompletion;

if (completion)
{
animationOptions.transitionFinishFn = [completion]() {
dispatch_async(dispatch_get_main_queue(), ^{
__weak __typeof__(self) weakSelf = self;

pendingCompletion = ^{
if (![weakSelf addPendingBlock:completion])
{
completion();
});
}
};

animationOptions.transitionFinishFn = [pendingCompletion]() {
dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}

if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, edgePadding))
{
if (completion)
if (pendingCompletion)
{
[self animateWithDelay:duration animations:^{
completion();
}];
[self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
Expand Down Expand Up @@ -3605,22 +3677,30 @@ - (void)_flyToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets wit
animationOptions.minZoom = MGLZoomLevelForAltitude(peakAltitude, peakPitch,
peakLatitude, self.frame.size);
}

dispatch_block_t pendingCompletion;

if (completion)
{
animationOptions.transitionFinishFn = [completion]() {
dispatch_async(dispatch_get_main_queue(), ^{
__weak __typeof__(self) weakSelf = self;

pendingCompletion = ^{
if (![weakSelf addPendingBlock:completion])
{
completion();
});
}
};

animationOptions.transitionFinishFn = [pendingCompletion]() {
dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}

if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
if (completion)
if (pendingCompletion)
{
[self animateWithDelay:duration animations:^{
completion();
}];
[self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
Expand Down

0 comments on commit 89853dd

Please sign in to comment.