@@ -21,6 +21,7 @@ @interface ASRangeControllerBeta ()
2121{
2222 BOOL _rangeIsValid;
2323 BOOL _queuedRangeUpdate;
24+ BOOL _layoutControllerImplementsSetVisibleIndexPaths;
2425 ASScrollDirection _scrollDirection;
2526 NSSet <NSIndexPath *> *_allPreviousIndexPaths;
2627}
@@ -58,43 +59,49 @@ - (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scr
5859 });
5960}
6061
62+ - (void )setLayoutController : (id <ASLayoutController>)layoutController
63+ {
64+ _layoutController = layoutController;
65+ _layoutControllerImplementsSetVisibleIndexPaths = [_layoutController respondsToSelector: @selector (setVisibleNodeIndexPaths: )];
66+ }
67+
6168- (void )_updateVisibleNodeIndexPaths
6269{
63- if (!_queuedRangeUpdate) {
70+ ASDisplayNodeAssert (_layoutController, @" An ASLayoutController is required by ASRangeController" );
71+ if (!_queuedRangeUpdate || !_layoutController) {
6472 return ;
6573 }
6674
67- // FIXME: Consider if we need to check this separately from the range calculation below.
75+ // TODO: Consider if we need to use this codepath, or can rely on something more similar to the data & display ranges
76+ // Example: ... = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
6877 NSArray <NSIndexPath *> *visibleNodePaths = [_dataSource visibleNodeIndexPathsForRangeController: self ];
6978
7079 if (visibleNodePaths.count == 0 ) { // if we don't have any visibleNodes currently (scrolled before or after content)...
7180 _queuedRangeUpdate = NO ;
7281 return ; // don't do anything for this update, but leave _rangeIsValid == NO to make sure we update it later
7382 }
7483
75- CGSize viewportSize = [_dataSource viewportSizeForRangeController: self ];
76- [_layoutController setViewportSize: viewportSize];
84+ [_layoutController setViewportSize: [_dataSource viewportSizeForRangeController: self ]];
7785
7886 // the layout controller needs to know what the current visible indices are to calculate range offsets
79- if ([_layoutController respondsToSelector: @selector ( setVisibleNodeIndexPaths: )] ) {
87+ if (_layoutControllerImplementsSetVisibleIndexPaths ) {
8088 [_layoutController setVisibleNodeIndexPaths: visibleNodePaths];
8189 }
8290
83- NSArray <NSArray *> *allNodes = [_dataSource completedNodes ]; // 2D array: section arrays, each containing nodes.
84- NSArray <ASDisplayNode *> *currentSectionNodes = nil ;
85- NSInteger currentSectionIndex = -1 ; // Will be unequal to any indexPath.section, so we set currentSectionNodes.
86-
91+ // allNodes is a 2D array: it contains arrays for each section, each containing nodes.
92+ NSArray <NSArray *> *allNodes = [_dataSource completedNodes ];
8793 NSUInteger numberOfSections = [allNodes count ];
94+
95+ NSArray <ASDisplayNode *> *currentSectionNodes = nil ;
96+ NSInteger currentSectionIndex = -1 ; // Set to -1 so we don't match any indexPath.section on the first iteration.
8897 NSUInteger numberOfNodesInSection = 0 ;
8998
90- NSSet <NSIndexPath *> *visibleIndexPaths = [NSSet setWithArray: visibleNodePaths];
91- // = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
99+ NSSet <NSIndexPath *> *visibleIndexPaths = [NSSet setWithArray: visibleNodePaths];
92100 NSSet <NSIndexPath *> *displayIndexPaths = nil ;
93101 NSSet <NSIndexPath *> *fetchDataIndexPaths = nil ;
94- NSMutableArray <NSIndexPath *> *modifiedIndexPaths = (RangeControllerLoggingEnabled ? [NSMutableArray array ] : nil );
95102
96103 // Prioritize the order in which we visit each. Visible nodes should be updated first so they are enqueued on
97- // the network or display queues before offscreen, preloading nodes are.
104+ // the network or display queues before preloading (offscreen) nodes are enqueued .
98105 NSMutableOrderedSet <NSIndexPath *> *allIndexPaths = [[NSMutableOrderedSet alloc ] initWithSet: visibleIndexPaths];
99106
100107 ASInterfaceState selfInterfaceState = [_dataSource interfaceStateForRangeController: self ];
@@ -107,20 +114,21 @@ - (void)_updateVisibleNodeIndexPaths
107114 // Typically the fetchDataIndexPaths will be the largest, and be a superset of the others, though it may be disjoint.
108115 // Because allIndexPaths is an NSMutableOrderedSet, this adds the non-duplicate items /after/ the existing items.
109116 // This means that during iteration, we will first visit visible, then display, then fetch data nodes.
110- // Nodes within the visible range may be getting their first display and fetch data call too, so enqueue them first.
111117 [allIndexPaths unionSet: displayIndexPaths];
112118 [allIndexPaths unionSet: fetchDataIndexPaths];
113119 }
114120
115- // Sets are magical. Add anything we had applied interfaceState to in the last update, so we can clear any
121+ // Add anything we had applied interfaceState to in the last update, but is no longer in range , so we can clear any
116122 // range flags it still has enabled. Most of the time, all but a few elements are equal; a large programmatic
117- // scroll or major main thread stall could cause entirely disjoint sets, but we must visit all.
118-
119- // Calling set on NSMutableOrderedSet just references the underlying data store, so we must copy it.
123+ // scroll or major main thread stall could cause entirely disjoint sets. In either case we must visit all.
124+ // Calling "-set" on NSMutableOrderedSet just references the underlying mutable data store, so we must copy it.
120125 NSSet <NSIndexPath *> *allCurrentIndexPaths = [[allIndexPaths set ] copy ];
121126 [allIndexPaths unionSet: _allPreviousIndexPaths];
122127 _allPreviousIndexPaths = allCurrentIndexPaths;
123-
128+
129+ // This array is only used if logging is enabled.
130+ NSMutableArray <NSIndexPath *> *modifiedIndexPaths = (RangeControllerLoggingEnabled ? [NSMutableArray array ] : nil );
131+
124132 for (NSIndexPath *indexPath in allIndexPaths) {
125133 // Before a node / indexPath is exposed to ASRangeController, ASDataController should have already measured it.
126134 // For consistency, make sure each node knows that it should measure itself if something changes.
0 commit comments