From b908c08ac2367652249918f4f5694eaf17a1eac2 Mon Sep 17 00:00:00 2001 From: "Wanseob (Eric) Kim" Date: Tue, 15 Aug 2017 11:35:13 -0700 Subject: [PATCH] Issue1176 improve ios marker performance by X100 (#1187) * Issue1176 attempt to fix UI lag success by re-using UIImage * Now use NSMutableDictionary instead of single UIImage * appearAnimation happen at init rather than setIcon * Init NSMutableDictionary * Remove reference to other app --- lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m | 80 +++++----------------- lib/ios/AirGoogleMaps/GlobalVars.h | 22 ++++++ lib/ios/AirGoogleMaps/GlobalVars.m | 54 +++++++++++++++ 3 files changed, 92 insertions(+), 64 deletions(-) create mode 100644 lib/ios/AirGoogleMaps/GlobalVars.h create mode 100644 lib/ios/AirGoogleMaps/GlobalVars.m diff --git a/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m index c41be55bbb..9d96dfafc1 100644 --- a/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m +++ b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m @@ -12,6 +12,7 @@ #import "AIRGMSMarker.h" #import "AIRGoogleMapCallout.h" #import "DummyView.h" +#import "GlobalVars.h" CGRect unionRect(CGRect a, CGRect b) { return CGRectMake( @@ -36,6 +37,7 @@ - (instancetype)init if ((self = [super init])) { _realMarker = [[AIRGMSMarker alloc] init]; _realMarker.fakeMarker = self; + _realMarker.appearAnimation = kGMSMarkerAnimationPop; } return self; } @@ -92,6 +94,18 @@ - (void)insertReactSubview:(id)subview atIndex:(NSInteger)atIndex [super insertReactSubview:(UIView*)dummySubview atIndex:atIndex]; } +- (void)setIcon:(UIImage*)image { + CGImageRef cgref = [image CGImage]; + CIImage *cim = [image CIImage]; + + if (cim == nil && cgref == NULL) { + // image does not contain image data + _realMarker.icon = [GMSMarker markerImageWithColor:UIColor.blueColor]; + } else { + _realMarker.icon = image; + } +} + - (void)removeReactSubview:(id)dummySubview { UIView* subview = ((DummyView*)dummySubview).view; @@ -188,70 +202,8 @@ - (void)setOpacity:(double)opacity - (void)setImageSrc:(NSString *)imageSrc { - _imageSrc = imageSrc; - - if (_reloadImageCancellationBlock) { - _reloadImageCancellationBlock(); - _reloadImageCancellationBlock = nil; - } - - if (!_imageSrc) { - if (_iconImageView) [_iconImageView removeFromSuperview]; - return; - } - - if (!_iconImageView) { - // prevent glitch with marker (cf. https://github.com/airbnb/react-native-maps/issues/738) - UIImageView *empyImageView = [[UIImageView alloc] init]; - _iconImageView = empyImageView; - [self iconViewInsertSubview:_iconImageView atIndex:0]; - } - - _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] - size:self.bounds.size - scale:RCTScreenScale() - clipped:YES - resizeMode:RCTResizeModeCenter - progressBlock:nil - partialLoadBlock:nil - completionBlock:^(NSError *error, UIImage *image) { - if (error) { - // TODO(lmr): do something with the error? - NSLog(@"%@", error); - } - dispatch_async(dispatch_get_main_queue(), ^{ - - // TODO(gil): This way allows different image sizes - if (_iconImageView) [_iconImageView removeFromSuperview]; - - // ... but this way is more efficient? -// if (_iconImageView) { -// [_iconImageView setImage:image]; -// return; -// } - - UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; - - // TODO: w,h or pixel density could be a prop. - float density = 1; - float w = image.size.width/density; - float h = image.size.height/density; - CGRect bounds = CGRectMake(0, 0, w, h); - - imageView.contentMode = UIViewContentModeScaleAspectFit; - [imageView setFrame:bounds]; - - // NOTE: sizeToFit doesn't work instead. Not sure why. - // TODO: Doing it this way is not ideal because it causes things to reshuffle - // when the image loads IF the image is larger than the UIView. - // Shouldn't required images have size info automatically via RN? - CGRect selfBounds = unionRect(bounds, self.bounds); - [self setFrame:selfBounds]; - - _iconImageView = imageView; - [self iconViewInsertSubview:imageView atIndex:0]; - }); - }]; + UIImage * image = [[GlobalVars sharedInstance] getSharedUIImage:imageSrc]; + [self setIcon:image]; } - (void)setTitle:(NSString *)title { diff --git a/lib/ios/AirGoogleMaps/GlobalVars.h b/lib/ios/AirGoogleMaps/GlobalVars.h new file mode 100644 index 0000000000..86c3555f7a --- /dev/null +++ b/lib/ios/AirGoogleMaps/GlobalVars.h @@ -0,0 +1,22 @@ +// +// GlobalVars.h +// +// Created by Eric Kim on 2017-04-04. +// Copyright © 2017 Apply Digital. All rights reserved. +// + +#import +#import + +@interface GlobalVars : NSObject +{ + NSMutableDictionary *dict; +} + ++ (GlobalVars *)sharedInstance; + +- (UIImage *)getSharedUIImage:(NSString *)imageSrc; + +@property(strong, nonatomic, readwrite) NSMutableDictionary *dict; + +@end diff --git a/lib/ios/AirGoogleMaps/GlobalVars.m b/lib/ios/AirGoogleMaps/GlobalVars.m new file mode 100644 index 0000000000..7a541dab41 --- /dev/null +++ b/lib/ios/AirGoogleMaps/GlobalVars.m @@ -0,0 +1,54 @@ +// +// GlobalVars.m +// +// Created by Eric Kim on 2017-04-04. +// Copyright © 2017 Apply Digital. All rights reserved. +// + +#import "GlobalVars.h" + +@implementation GlobalVars + +@synthesize dict = _dict; + ++ (GlobalVars *)sharedInstance { + static dispatch_once_t onceToken; + static GlobalVars *instance = nil; + dispatch_once(&onceToken, ^{ + instance = [[GlobalVars alloc] init]; + }); + return instance; +} + +- (UIImage *)getSharedUIImage:(NSString *)imageSrc { + + UIImage* cachedImage = dict[imageSrc]; + + CGImageRef cgref = [cachedImage CGImage]; + CIImage *cim = [cachedImage CIImage]; + + if (cim == nil && cgref == NULL) { + UIImage *newImage; + if ([imageSrc hasPrefix:@"http://"] || [imageSrc hasPrefix:@"https://"]){ + NSURL *url = [NSURL URLWithString:imageSrc]; + NSData *data = [NSData dataWithContentsOfURL:url]; + newImage = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale]; + } else { + newImage = [UIImage imageWithContentsOfFile:imageSrc]; + } + dict[imageSrc] = newImage; + return newImage; + } else { + return cachedImage; + } +} + +- (id)init { + self = [super init]; + if (self) { + dict = [[NSMutableDictionary alloc] init]; + } + return self; +} + +@end