123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #import "PSTCollectionViewData.h"
- #import "PSTCollectionView.h"
- @interface PSTCollectionViewData () {
- CGRect _validLayoutRect;
- NSInteger _numItems;
- NSInteger _numSections;
- NSInteger *_sectionItemCounts;
-
- CGSize _contentSize;
- struct {
- unsigned int contentSizeIsValid:1;
- unsigned int itemCountsAreValid:1;
- unsigned int layoutIsPrepared:1;
- }_collectionViewDataFlags;
- }
- @property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView;
- @property (nonatomic, unsafe_unretained) PSTCollectionViewLayout *layout;
- @property (nonatomic, strong) NSArray *cachedLayoutAttributes;
- @end
- @implementation PSTCollectionViewData
- #pragma mark - NSObject
- - (id)initWithCollectionView:(PSTCollectionView *)collectionView layout:(PSTCollectionViewLayout *)layout {
- if ((self = [super init])) {
- _collectionView = collectionView;
- _layout = layout;
- }
- return self;
- }
- - (void)dealloc {
- free(_sectionItemCounts);
- }
- - (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p numItems:%ld numSections:%ld>", NSStringFromClass(self.class), self, (long)self.numberOfItems, (long)self.numberOfSections];
- }
- #pragma mark - Public
- - (void)invalidate {
- _collectionViewDataFlags.itemCountsAreValid = NO;
- _collectionViewDataFlags.layoutIsPrepared = NO;
- _validLayoutRect = CGRectNull;
- }
- - (CGRect)collectionViewContentRect {
- return (CGRect){.size=_contentSize};
- }
- - (void)validateLayoutInRect:(CGRect)rect {
- [self validateItemCounts];
- [self prepareToLoadData];
-
- if (!CGRectEqualToRect(_validLayoutRect, rect)) {
- _validLayoutRect = rect;
-
- self.cachedLayoutAttributes = [[self.layout layoutAttributesForElementsInRect:rect] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(PSTCollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) {
- return ([evaluatedObject isKindOfClass:PSTCollectionViewLayoutAttributes.class] &&
- ([evaluatedObject isCell] ||
- [evaluatedObject isSupplementaryView] ||
- [evaluatedObject isDecorationView]));
- }]];
- }
- }
- - (NSInteger)numberOfItems {
- [self validateItemCounts];
- return _numItems;
- }
- - (NSInteger)numberOfItemsBeforeSection:(NSInteger)section {
- [self validateItemCounts];
- NSAssert(section < _numSections, @"request for number of items in section %ld when there are only %ld sections in the collection view", (long)section, (long)_numSections);
- NSInteger returnCount = 0;
- for (int i = 0; i < section; i++) {
- returnCount += _sectionItemCounts[i];
- }
- return returnCount;
- }
- - (NSInteger)numberOfItemsInSection:(NSInteger)section {
- [self validateItemCounts];
- if (section >= _numSections || section < 0) {
-
-
-
- return 0;
-
- }
- NSInteger numberOfItemsInSection = 0;
- if (_sectionItemCounts) {
- numberOfItemsInSection = _sectionItemCounts[section];
- }
- return numberOfItemsInSection;
- }
- - (NSInteger)numberOfSections {
- [self validateItemCounts];
- return _numSections;
- }
- - (CGRect)rectForItemAtIndexPath:(NSIndexPath *)indexPath {
- return CGRectZero;
- }
- - (NSIndexPath *)indexPathForItemAtGlobalIndex:(NSInteger)index {
- [self validateItemCounts];
- NSAssert(index < _numItems, @"request for index path for global index %ld when there are only %ld items in the collection view", (long)index, (long)_numItems);
- NSInteger section = 0;
- NSInteger countItems = 0;
- for (section = 0; section < _numSections; section++) {
- NSInteger countIncludingThisSection = countItems + _sectionItemCounts[section];
- if (countIncludingThisSection > index) break;
- countItems = countIncludingThisSection;
- }
- NSInteger item = index - countItems;
- return [NSIndexPath indexPathForItem:item inSection:section];
- }
- - (NSUInteger)globalIndexForItemAtIndexPath:(NSIndexPath *)indexPath {
- NSInteger offset = [self numberOfItemsBeforeSection:indexPath.section] + indexPath.item;
- return (NSUInteger)offset;
- }
- - (BOOL)layoutIsPrepared {
- return _collectionViewDataFlags.layoutIsPrepared;
- }
- - (void)setLayoutIsPrepared:(BOOL)layoutIsPrepared {
- _collectionViewDataFlags.layoutIsPrepared = (unsigned int)layoutIsPrepared;
- }
- #pragma mark - Fetch Layout Attributes
- - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
- [self validateLayoutInRect:rect];
- return self.cachedLayoutAttributes;
- }
- #pragma mark - Private
- - (void)validateItemCounts {
- if (!_collectionViewDataFlags.itemCountsAreValid) {
- [self updateItemCounts];
- }
- }
- - (void)updateItemCounts {
-
- _numSections = 1;
- if ([self.collectionView.dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
- _numSections = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView];
- }
- if (_numSections <= 0) {
- _numItems = 0;
- free(_sectionItemCounts);
- _sectionItemCounts = 0;
- _collectionViewDataFlags.itemCountsAreValid = YES;
- return;
- }
-
- if (!_sectionItemCounts) {
- _sectionItemCounts = malloc((size_t)_numSections * sizeof(NSInteger));
- }else {
- _sectionItemCounts = realloc(_sectionItemCounts, (size_t)_numSections * sizeof(NSInteger));
- }
-
- _numItems = 0;
- for (NSInteger i = 0; i < _numSections; i++) {
- NSInteger cellCount = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:i];
- _sectionItemCounts[i] = cellCount;
- _numItems += cellCount;
- }
- _collectionViewDataFlags.itemCountsAreValid = YES;
- }
- - (void)prepareToLoadData {
- if (!self.layoutIsPrepared) {
- [self.layout prepareLayout];
- _contentSize = self.layout.collectionViewContentSize;
- self.layoutIsPrepared = YES;
- }
- }
- @end
|