Asyncdisplaykit: [Discussion] Solutions to eliminate flashes caused by reloadData

Created on 2 Nov 2016  Β·  10Comments  Β·  Source: facebookarchive/AsyncDisplayKit

So I’ve been thinking about ways to eliminate, or at least minimize, flashes caused by reloadData. This is one of the top complaints from developers that are new to the framework. I have a couple of solutions in mind and would love to start a discussion here:

  • Cell node prioritization:

    • I reckon one of the main causes of flashing is due to the fact that new cell nodes are initialized and laid out linearly, meaning they are handled from first to last index. Instead, we should have prioritized them based on the ranges. Nodes in visible range should be handled first, followed by the ones in fetch data range and so on. We can even block main thread while dealing with the highest priority nodes (i.e. visible ones).
    • One possible issue with this technique is that it needs to maintain content offset of the scroll view. In other words, we need to keep a static viewport while deleting/inserting nodes.
    • This solution maybe easier to implement once virtualization is supported, or maybe a step toward virtualization.
  • Another way to solve this problem is hiding external components (esp. the underlying table/collection view) from the fact that reloadDatais broken down into a series of deletions and insertions. What it means is that, while making changes to the data set, we don't notify ASDataControllerDelegate at all. Then once we finished loading all cells, the delegate will be notified about a single atomic reload operation.

I believe either of these solutions can eliminate the flash. Although it will make developers less likely to do batch update :(

cc @Adlai-Holler @maicki @garrettmoon @appleguy

Development in Progress Enhancement P2

Most helpful comment

@shellhue I think the cells flash because they are asynchronously displayed and so for a short time their contents are not ready yet. Try setting neverShowPlaceholders to YES on the cell nodes. More information can be found here.

All 10 comments

@nguyenhuy does @Adlai-Holler 's PR address this? Can it be closed?

@garrettmoon: it does partially address this issue. But I'm having an improvement in mind, will report back this week.

@nguyenhuy - could you update this thread? I know you've been working on improvements in this area. :)

3017 implements the 2nd approach mentioned above. Flashes are gone now.

i don't think flashes are gone. i create a simple table node with a cell containing just a image node and text node. If i call [tableNode reloadData], sometimes there is no flash, but for half of the time flash happens. I am at the latest commit of branch master.

@shellhue Are you seeing flashes at the image and text nodes level? Could you please post a video? There is a chance that we're talking about different kinds of flashes here :)

asyncdisplaykitflash.mov.zip
i have uploaded the demo video.

the view controller code is very simple.

#import "ViewController.h"
#import "BLCellNode.h"

@interface ViewController () <ASTableDelegate, ASTableDataSource>
@property (nonatomic, strong) ASTableNode *tableNode;
@end

@implementation ViewController
- (instancetype)init {
  self = [super initWithNode:[ASDisplayNode new]];
  if (self) {

  }
  return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
  self.view.backgroundColor = [UIColor redColor];
  self.tableNode = ({
    ASTableNode *node = [ASTableNode new];
    node.delegate = self;
    node.dataSource = self;
    node;
  });

  [self.node addSubnode:self.tableNode];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidLayoutSubviews {
  [super viewDidLayoutSubviews];
  self.tableNode.frame = self.view.bounds;
}

- (void)refresh {
  [self.tableNode reloadData];
}

- (NSInteger)tableNode:(ASTableNode *)tableNode numberOfRowsInSection:(NSInteger)section {
  return 2;
}

- (ASCellNode *)tableNode:(ASTableNode *)tableNode nodeForRowAtIndexPath:(NSIndexPath *)indexPath {
  return [BLCellNode new];
}

@end

BLCellNode is as below:

#import "BLCellNode.h"
@interface BLCellNode ()
@property (nonatomic, strong) ASImageNode *imageNode;
@property (nonatomic, strong) ASTextNode *textNode;
@end
@implementation BLCellNode
- (instancetype)init {
  self = [super init];
  if (self) {
    self.imageNode = [ASImageNode new];
    self.imageNode.image = [UIImage imageNamed:@"sample"];
    self.imageNode.style.height = ASDimensionMake(300);
    [self addSubnode:self.imageNode];

    self.textNode = [ASTextNode new];
    NSDictionary *attributes = @{
                                 NSFontAttributeName: [UIFont systemFontOfSize:16]
                                 };
    self.textNode.attributedText = [[NSAttributedString alloc] initWithString:@"η«‹εˆ»ε›žε€ζ‹‰θ¨η²‰ηΊ’θ‰²ε•¦ηœ‹ι£Žζ™―εΌ—ε…°ε…‹ζ’’εŠ ζŠ€θ‚€θ€εΈˆηš„ιžε’θ¨ε‘η»δ»£ι£ŽεŽθ€εΈˆηš„ε›žε€εΌ—ε…°ε…‹ηš„ζ’’θƒ‘ζ€’η²‰δΊ†ζ·±εˆ»ηš„η«‹εˆ»ε›žε€ζ‹‰θ¨η²‰ηΊ’θ‰²ε•¦ηœ‹ι£Žζ™―εΌ—ε…°ε…‹ζ’’εŠ ζŠ€θ‚€θ€εΈˆηš„ιžε’θ¨ε‘η»δ»£ι£ŽεŽθ€εΈˆηš„ε›žε€εΌ—ε…°ε…‹ηš„ζ’’θƒ‘ζ€’η²‰δΊ†ζ·±εˆ»ηš„η«‹εˆ»ε›žε€ζ‹‰θ¨η²‰ηΊ’θ‰²ε•¦ηœ‹ι£Žζ™―εΌ—ε…°ε…‹ζ’’εŠ ζŠ€θ‚€θ€εΈˆηš„ιžε’θ¨ε‘η»δ»£ι£ŽεŽθ€εΈˆηš„ε›žε€εΌ—ε…°ε…‹ηš„ζ’’θƒ‘ζ€’η²‰δΊ†ζ·±εˆ»ηš„η«‹εˆ»ε›žε€ζ‹‰θ¨η²‰ηΊ’θ‰²ε•¦ηœ‹ι£Žζ™―εΌ—ε…°ε…‹ζ’’εŠ ζŠ€θ‚€θ€εΈˆηš„ιžε’θ¨ε‘η»δ»£ι£ŽεŽθ€εΈˆηš„ε›žε€εΌ—ε…°ε…‹ηš„ζ’’θƒ‘ζ€’η²‰δΊ†ζ·±εˆ»ηš„" attributes:attributes];
    [self addSubnode:self.textNode];
  }
  return self;
}

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize {
 return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:10 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsCenter children:@[self.imageNode, self.textNode]];
}


@end

@shellhue I think the cells flash because they are asynchronously displayed and so for a short time their contents are not ready yet. Try setting neverShowPlaceholders to YES on the cell nodes. More information can be found here.

Yeah, you are right, after setting neverShowPlaceholders to YES, the flashes are gone. Our team uses AsyncDisplayKit heavily, but this kind of flash makes us limit the use, especially when there is a lot of refresh. Thanks very much.

@shellhue You're welcome! I'm glad to hear that you're unblocked! Feel free to join our Slack channel for even faster Q&A!

Was this page helpful?
0 / 5 - 0 ratings