Skip to content

Commit

Permalink
Issue1176 improve ios marker performance by X100 (react-native-maps#1187
Browse files Browse the repository at this point in the history
)

* 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
  • Loading branch information
ericapply authored and codedre committed Aug 15, 2017
1 parent b360280 commit 8df4817
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 64 deletions.
80 changes: 16 additions & 64 deletions lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import "AIRGMSMarker.h"
#import "AIRGoogleMapCallout.h"
#import "DummyView.h"
#import "GlobalVars.h"

CGRect unionRect(CGRect a, CGRect b) {
return CGRectMake(
Expand All @@ -36,6 +37,7 @@ - (instancetype)init
if ((self = [super init])) {
_realMarker = [[AIRGMSMarker alloc] init];
_realMarker.fakeMarker = self;
_realMarker.appearAnimation = kGMSMarkerAnimationPop;
}
return self;
}
Expand Down Expand Up @@ -92,6 +94,18 @@ - (void)insertReactSubview:(id<RCTComponent>)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<RCTComponent>)dummySubview {
UIView* subview = ((DummyView*)dummySubview).view;

Expand Down Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions lib/ios/AirGoogleMaps/GlobalVars.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// GlobalVars.h
//
// Created by Eric Kim on 2017-04-04.
// Copyright © 2017 Apply Digital. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface GlobalVars : NSObject
{
NSMutableDictionary *dict;
}

+ (GlobalVars *)sharedInstance;

- (UIImage *)getSharedUIImage:(NSString *)imageSrc;

@property(strong, nonatomic, readwrite) NSMutableDictionary *dict;

@end
54 changes: 54 additions & 0 deletions lib/ios/AirGoogleMaps/GlobalVars.m
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8df4817

Please sign in to comment.