diff --git a/ios/FastImage/FFFastImageView.m b/ios/FastImage/FFFastImageView.m index 5fa8d91..581794b 100644 --- a/ios/FastImage/FFFastImageView.m +++ b/ios/FastImage/FFFastImageView.m @@ -1,11 +1,17 @@ #import "FFFastImageView.h" -@implementation FFFastImageView { - BOOL hasSentOnLoadStart; - BOOL hasCompleted; - BOOL hasErrored; - NSDictionary* onLoadEvent; -} + +@interface FFFastImageView() + +@property (nonatomic, assign) BOOL hasSentOnLoadStart; +@property (nonatomic, assign) BOOL hasCompleted; +@property (nonatomic, assign) BOOL hasErrored; + +@property (nonatomic, strong) NSDictionary* onLoadEvent; + +@end + +@implementation FFFastImageView - (id) init { self = [super init]; @@ -14,53 +20,63 @@ return self; } -- (void)setResizeMode:(RCTResizeMode)resizeMode -{ +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +- (void)setResizeMode:(RCTResizeMode)resizeMode { if (_resizeMode != resizeMode) { _resizeMode = resizeMode; self.contentMode = (UIViewContentMode)resizeMode; } } -- (void)setOnFastImageLoadEnd:(RCTBubblingEventBlock)onFastImageLoadEnd { +- (void)setOnFastImageLoadEnd:(RCTDirectEventBlock)onFastImageLoadEnd { _onFastImageLoadEnd = onFastImageLoadEnd; - if (hasCompleted) { + if (self.hasCompleted) { _onFastImageLoadEnd(@{}); } } -- (void)setOnFastImageLoad:(RCTBubblingEventBlock)onFastImageLoad { +- (void)setOnFastImageLoad:(RCTDirectEventBlock)onFastImageLoad { _onFastImageLoad = onFastImageLoad; - if (hasCompleted) { - _onFastImageLoad(onLoadEvent); + if (self.hasCompleted) { + _onFastImageLoad(self.onLoadEvent); } } - (void)setOnFastImageError:(RCTDirectEventBlock)onFastImageError { _onFastImageError = onFastImageError; - if (hasErrored) { + if (self.hasErrored) { _onFastImageError(@{}); } } -- (void)setOnFastImageLoadStart:(RCTBubblingEventBlock)onFastImageLoadStart { - if (_source && !hasSentOnLoadStart) { +- (void)setOnFastImageLoadStart:(RCTDirectEventBlock)onFastImageLoadStart { + if (_source && !self.hasSentOnLoadStart) { _onFastImageLoadStart = onFastImageLoadStart; onFastImageLoadStart(@{}); - hasSentOnLoadStart = YES; + self.hasSentOnLoadStart = YES; } else { _onFastImageLoadStart = onFastImageLoadStart; - hasSentOnLoadStart = NO; + self.hasSentOnLoadStart = NO; } } - (void)sendOnLoad:(UIImage *)image { - onLoadEvent = @{ - @"width":[NSNumber numberWithDouble:image.size.width], - @"height":[NSNumber numberWithDouble:image.size.height] - }; - if (_onFastImageLoad) { - _onFastImageLoad(onLoadEvent); + self.onLoadEvent = @{ + @"width":[NSNumber numberWithDouble:image.size.width], + @"height":[NSNumber numberWithDouble:image.size.height] + }; + if (self.onFastImageLoad) { + self.onFastImageLoad(self.onLoadEvent); + } +} + +- (void)imageDidLoadObserver:(NSNotification *)notification { + FFFastImageSource *source = notification.object; + if (source != nil && source.url != nil) { + [self sd_setImageWithURL:source.url]; } } @@ -68,28 +84,31 @@ if (_source != source) { _source = source; + // Attach a observer to refresh other FFFastImageView instance sharing the same source + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(imageDidLoadObserver:) name:source.url.absoluteString object:nil]; + // Load base64 images. NSString* url = [_source.url absoluteString]; if (url && [url hasPrefix:@"data:image"]) { - if (_onFastImageLoadStart) { - _onFastImageLoadStart(@{}); - hasSentOnLoadStart = YES; + if (self.onFastImageLoadStart) { + self.onFastImageLoadStart(@{}); + self.hasSentOnLoadStart = YES; } { - hasSentOnLoadStart = NO; + self.hasSentOnLoadStart = NO; } UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:_source.url]]; [self setImage:image]; - if (_onFastImageProgress) { - _onFastImageProgress(@{ - @"loaded": @(1), - @"total": @(1) - }); + if (self.onFastImageProgress) { + self.onFastImageProgress(@{ + @"loaded": @(1), + @"total": @(1) + }); } - hasCompleted = YES; + self.hasCompleted = YES; [self sendOnLoad:image]; - if (_onFastImageLoadEnd) { - _onFastImageLoadEnd(@{}); + if (self.onFastImageLoadEnd) { + self.onFastImageLoadEnd(@{}); } return; } @@ -100,8 +119,7 @@ }]; // Set priority. - SDWebImageOptions options = 0; - options |= SDWebImageRetryFailed; + SDWebImageOptions options = SDWebImageRetryFailed; switch (_source.priority) { case FFFPriorityLow: options |= SDWebImageLowPriority; @@ -125,53 +143,56 @@ break; } - if (_onFastImageLoadStart) { - _onFastImageLoadStart(@{}); - hasSentOnLoadStart = YES; + if (self.onFastImageLoadStart) { + self.onFastImageLoadStart(@{}); + self.hasSentOnLoadStart = YES; } { - hasSentOnLoadStart = NO; + self.hasSentOnLoadStart = NO; } - hasCompleted = NO; - hasErrored = NO; + self.hasCompleted = NO; + self.hasErrored = NO; - // Load the new source. - // This will work for: - // - https:// - // - file:///var/containers/Bundle/Application/50953EA3-CDA8-4367-A595-DE863A012336/ReactNativeFastImageExample.app/assets/src/images/fields.jpg - // - file:///var/containers/Bundle/Application/545685CB-777E-4B07-A956-2D25043BC6EE/ReactNativeFastImageExample.app/assets/src/images/plankton.gif - // - file:///Users/dylan/Library/Developer/CoreSimulator/Devices/61DC182B-3E72-4A18-8908-8A947A63A67F/data/Containers/Data/Application/AFC2A0D2-A1E5-48C1-8447-C42DA9E5299D/Documents/images/E1F1D5FC-88DB-492F-AD33-B35A045D626A.jpg" - [self sd_setImageWithURL:_source.url - placeholderImage:nil - options:options - progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { - if (_onFastImageProgress) { - _onFastImageProgress(@{ - @"loaded": @(receivedSize), - @"total": @(expectedSize) - }); - } - } completed:^(UIImage * _Nullable image, - NSError * _Nullable error, - SDImageCacheType cacheType, - NSURL * _Nullable imageURL) { - if (error) { - hasErrored = YES; - if (_onFastImageError) { - _onFastImageError(@{}); - } - if (_onFastImageLoadEnd) { - _onFastImageLoadEnd(@{}); - } - } else { - hasCompleted = YES; - [self sendOnLoad:image]; - if (_onFastImageLoadEnd) { - _onFastImageLoadEnd(@{}); - } - } - }]; + [self downloadImage:_source options:options]; } } +- (void)downloadImage:(FFFastImageSource *) source options:(SDWebImageOptions) options { + __weak typeof(self) weakSelf = self; // Always use a weak reference to self in blocks + [self sd_setImageWithURL:_source.url + placeholderImage:nil + options:options + progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + if (weakSelf.onFastImageProgress) { + weakSelf.onFastImageProgress(@{ + @"loaded": @(receivedSize), + @"total": @(expectedSize) + }); + } + } completed:^(UIImage * _Nullable image, + NSError * _Nullable error, + SDImageCacheType cacheType, + NSURL * _Nullable imageURL) { + if (error) { + weakSelf.hasErrored = YES; + if (weakSelf.onFastImageError) { + weakSelf.onFastImageError(@{}); + } + if (weakSelf.onFastImageLoadEnd) { + weakSelf.onFastImageLoadEnd(@{}); + } + } else { + weakSelf.hasCompleted = YES; + [weakSelf sendOnLoad:image]; + + // Alert other FFFastImageView component sharing the same URL + [NSNotificationCenter.defaultCenter postNotificationName:source.url.absoluteString object:source]; + + if (weakSelf.onFastImageLoadEnd) { + weakSelf.onFastImageLoadEnd(@{}); + } + } + }]; +} + @end