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
This commit is contained in:
Ben Nham 2016-05-24 08:39:40 -07:00 committed by Facebook Github Bot 7
parent 7113367000
commit 71bf8a3e48
1 changed files with 23 additions and 18 deletions

View File

@ -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];
}
}