From 71bf8a3e48f8da93746938330aa3660b015af7c8 Mon Sep 17 00:00:00 2001 From: Ben Nham Date: Tue, 24 May 2016 08:39:40 -0700 Subject: [PATCH] Only clear image contents on memory warning Summary: Some apps are complaining about flashing images when performing navigation transitions. An example issue would be: 1. Load a master list view with many images 2. Click on an image to go to a detail view 3. Go back to the master list view At step (3), users see a number of images flash from a placeholder image back to the final image because `-[RCTImageView didMoveToWindow]` calls `clearImage` when the image view exits the view hierarchy between (1) and (2) and calls `reloadImage` (which sets the image property asynchronously) when the image view re-enters the view hiearchy between (2) and (3). This diff fixes the issue by being less aggressive about clearing image contents. It only clears image contents when the app receives a memory warning or the app goes into the background. For comparison, CKNetworkImageComponent in ComponentKit doesn't have this purging behavior at all. Reviewed By: javache Differential Revision: D3325009 fbshipit-source-id: efca10099cdfdb49afbb3f550854d4b8a40511d0 --- Libraries/Image/RCTImageView.m | 41 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index b805cd9b6..1376fb796 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -62,10 +62,25 @@ static BOOL RCTShouldReloadImageForSizeChange(CGSize currentSize, CGSize idealSi { if ((self = [super init])) { _bridge = bridge; + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(clearImageIfDetached) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; + [center addObserver:self + selector:@selector(clearImageIfDetached) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; } return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + RCT_NOT_IMPLEMENTED(- (instancetype)init) - (void)updateImage @@ -172,6 +187,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) self.image = nil; } +- (void)clearImageIfDetached +{ + if (!self.window) { + [self clearImage]; + } +} + - (void)reloadImage { [self cancelImageLoad]; @@ -294,24 +316,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) { [super didMoveToWindow]; - if (!self.window) { - // Don't keep self alive through the asynchronous dispatch, if the intention - // was to remove the view so it would deallocate. - __weak typeof(self) weakSelf = self; - - dispatch_async(dispatch_get_main_queue(), ^{ - __strong typeof(self) strongSelf = weakSelf; - if (!strongSelf) { - return; - } - - // If we haven't been re-added to a window by this run loop iteration, - // clear out the image to save memory. - if (!strongSelf.window) { - [strongSelf clearImage]; - } - }); - } else if (!self.image || self.image == _defaultImage) { + if (self.window && (!self.image || self.image == _defaultImage)) { [self reloadImage]; } }