From e35697d162f667047ae6b47835ac9e493262782a Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Wed, 23 Dec 2015 10:19:05 +0000 Subject: [PATCH] Greatly improve the internal logic of ASMapNode. Also fixes bug #971 --- AsyncDisplayKit/ASMapNode.h | 4 +- AsyncDisplayKit/ASMapNode.mm | 119 +++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/AsyncDisplayKit/ASMapNode.h b/AsyncDisplayKit/ASMapNode.h index acabf84152..bd2d23ad4b 100644 --- a/AsyncDisplayKit/ASMapNode.h +++ b/AsyncDisplayKit/ASMapNode.h @@ -12,7 +12,7 @@ @interface ASMapNode : ASImageNode /** - The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. + The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. This property may be set from a background thread before the node is loaded, and will automatically be applied to define the region of the static snapshot (if .liveMap = NO) or the internal MKMapView (otherwise). */ @property (nonatomic, assign) MKCoordinateRegion region; @@ -22,7 +22,7 @@ @property (nonatomic, readonly) MKMapView *mapView; /** - Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. + Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. This property may be set on a background thread before the node is loaded, and will automatically be actioned, once the node is loaded. */ @property (nonatomic, assign, getter=isLiveMap) BOOL liveMap; diff --git a/AsyncDisplayKit/ASMapNode.mm b/AsyncDisplayKit/ASMapNode.mm index 80a76fc82d..480360a1aa 100644 --- a/AsyncDisplayKit/ASMapNode.mm +++ b/AsyncDisplayKit/ASMapNode.mm @@ -26,6 +26,7 @@ @synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange; @synthesize mapDelegate = _mapDelegate; @synthesize region = _region; +@synthesize liveMap = _liveMap; #pragma mark - Lifecycle - (instancetype)init @@ -37,9 +38,11 @@ self.clipsToBounds = YES; _needsMapReloadOnBoundsChange = YES; - + _liveMap = NO; _centerCoordinateOfMap = kCLLocationCoordinate2DInvalid; - _region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(43.432858, 13.183671), MKCoordinateSpanMake(0.2, 0.2)); + + //Default world-scale view + _region = MKCoordinateRegionForMapRect(MKMapRectWorld); _options = [[MKMapSnapshotOptions alloc] init]; _options.region = _region; @@ -50,26 +53,31 @@ - (void)didLoad { [super didLoad]; - if ([self wasLiveMapPreviously]) { + if (self.isLiveMap) { self.userInteractionEnabled = YES; [self addLiveMap]; } } +- (void)setLayerBacked:(BOOL)layerBacked +{ + ASDisplayNodeAssert(!self.isLiveMap, @"ASMapNode can not be layer backed whilst .liveMap = YES, set .liveMap = NO to use layer backing."); + [super setLayerBacked:layerBacked]; +} + - (void)fetchData { [super fetchData]; - if ([self wasLiveMapPreviously]) { + if (self.isLiveMap) { [self addLiveMap]; } else { - [self setUpSnapshotter]; [self takeSnapshot]; } } -- (void)clearFetchedData +- (void)clearContents { - [super clearFetchedData]; + [super clearContents]; if (self.isLiveMap) { [self removeLiveMap]; } @@ -79,17 +87,21 @@ - (BOOL)isLiveMap { - return (_mapView != nil); + ASDN::MutexLocker l(_propertyLock); + return _liveMap; } - (void)setLiveMap:(BOOL)liveMap { - liveMap ? [self addLiveMap] : [self removeLiveMap]; -} - -- (BOOL)wasLiveMapPreviously -{ - return CLLocationCoordinate2DIsValid(_centerCoordinateOfMap); + ASDisplayNodeAssert(!self.isLayerBacked, @"ASMapNode can not use the interactive map feature whilst .isLayerBacked = YES, set .layerBacked = NO to use the interactive map feature."); + ASDN::MutexLocker l(_propertyLock); + if (liveMap == _liveMap) { + return; + } + _liveMap = liveMap; + if (self.nodeLoaded) { + liveMap ? [self addLiveMap] : [self removeLiveMap]; + } } - (BOOL)needsMapReloadOnBoundsChange @@ -127,63 +139,62 @@ - (void)takeSnapshot { - if (!_snapshotter.isLoading) { - [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { - if (!error) { - UIImage *image = snapshot.image; - CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); - - UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); - [image drawAtPoint:CGPointMake(0, 0)]; - - if (_annotations.count > 0 ) { - // Get a standard annotation view pin. Future implementations should use a custom annotation image property. - MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; - UIImage *pinImage = pin.image; - for (idannotation in _annotations) + if (!_snapshotter) { + [self setUpSnapshotter]; + } + [_snapshotter cancel]; + [_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) { + if (!error) { + UIImage *image = snapshot.image; + CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); + + UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale); + [image drawAtPoint:CGPointMake(0, 0)]; + + if (_annotations.count > 0 ) { + // Get a standard annotation view pin. Future implementations should use a custom annotation image property. + MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""]; + UIImage *pinImage = pin.image; + for (idannotation in _annotations) + { + CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; + if (CGRectContainsPoint(finalImageRect, point)) { - CGPoint point = [snapshot pointForCoordinate:annotation.coordinate]; - if (CGRectContainsPoint(finalImageRect, point)) - { - CGPoint pinCenterOffset = pin.centerOffset; - point.x -= pin.bounds.size.width / 2.0; - point.y -= pin.bounds.size.height / 2.0; - point.x += pinCenterOffset.x; - point.y += pinCenterOffset.y; - [pinImage drawAtPoint:point]; - } + CGPoint pinCenterOffset = pin.centerOffset; + point.x -= pin.bounds.size.width / 2.0; + point.y -= pin.bounds.size.height / 2.0; + point.x += pinCenterOffset.x; + point.y += pinCenterOffset.y; + [pinImage drawAtPoint:point]; } } - - UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - self.image = finalImage; } - }]; - } + + UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + self.image = finalImage; + } + }]; } - (void)setUpSnapshotter { - if (!_snapshotter) { - ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar."); - _options.size = self.calculatedSize; - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar."); + _options.size = self.calculatedSize; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; } - (void)resetSnapshotter { - if (!_snapshotter.isLoading) { - _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; - } + [_snapshotter cancel]; + _snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options]; } #pragma mark - Actions - (void)addLiveMap { ASDisplayNodeAssertMainThread(); - if (!self.isLiveMap) { + if (!_mapView) { __weak ASMapNode *weakSelf = self; _mapView = [[MKMapView alloc] initWithFrame:CGRectZero]; _mapView.delegate = weakSelf.mapDelegate; @@ -194,8 +205,6 @@ if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) { [_mapView setCenterCoordinate:_centerCoordinateOfMap]; - } else { - _centerCoordinateOfMap = _options.region.center; } } }