Skip to content

Commit 83d2194

Browse files
committed
This commit will fix the following crash:
* Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3505.16/UICollectionView.m:1519 *
1 parent a10f483 commit 83d2194

File tree

1 file changed

+99
-94
lines changed

1 file changed

+99
-94
lines changed

Classes/CSStickyHeaderFlowLayout.m

Lines changed: 99 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -68,108 +68,113 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind
6868

6969
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
7070
{
71-
// The rect should compensate the header size
72-
CGRect adjustedRect = rect;
73-
adjustedRect.origin.y -= self.parallaxHeaderReferenceSize.height;
74-
75-
NSMutableArray *allItems = [NSMutableArray array];
76-
NSArray *originalAttributes = [super layoutAttributesForElementsInRect:adjustedRect];
77-
//Perform a deep copy of the attributes returned from super
78-
for (UICollectionViewLayoutAttributes *originalAttribute in originalAttributes) {
79-
[allItems addObject:[originalAttribute copy]];
80-
}
8171

82-
NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];
83-
NSMutableDictionary *lastCells = [[NSMutableDictionary alloc] init];
84-
__block BOOL visibleParallexHeader;
85-
86-
[allItems enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
87-
UICollectionViewLayoutAttributes *attributes = obj;
88-
89-
CGRect frame = attributes.frame;
90-
frame.origin.y += self.parallaxHeaderReferenceSize.height;
91-
attributes.frame = frame;
92-
93-
NSIndexPath *indexPath = [(UICollectionViewLayoutAttributes *)obj indexPath];
94-
BOOL isHeader = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionHeader];
95-
BOOL isFooter = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionFooter];
96-
97-
if (isHeader) {
98-
[headers setObject:obj forKey:@(indexPath.section)];
99-
} else if (isFooter) {
100-
// Not implemeneted
101-
} else {
102-
UICollectionViewLayoutAttributes *currentAttribute = [lastCells objectForKey:@(indexPath.section)];
103-
104-
// Get the bottom most cell of that section
105-
if ( ! currentAttribute || indexPath.row > currentAttribute.indexPath.row) {
106-
[lastCells setObject:obj forKey:@(indexPath.section)];
72+
if (self.collectionView.dataSource != nil) {
73+
// The rect should compensate the header size
74+
CGRect adjustedRect = rect;
75+
adjustedRect.origin.y -= self.parallaxHeaderReferenceSize.height;
76+
77+
NSMutableArray *allItems = [NSMutableArray array];
78+
NSArray *originalAttributes = [super layoutAttributesForElementsInRect:adjustedRect];
79+
//Perform a deep copy of the attributes returned from super
80+
for (UICollectionViewLayoutAttributes *originalAttribute in originalAttributes) {
81+
[allItems addObject:[originalAttribute copy]];
82+
}
83+
84+
NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];
85+
NSMutableDictionary *lastCells = [[NSMutableDictionary alloc] init];
86+
__block BOOL visibleParallexHeader;
87+
88+
[allItems enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
89+
UICollectionViewLayoutAttributes *attributes = obj;
90+
91+
CGRect frame = attributes.frame;
92+
frame.origin.y += self.parallaxHeaderReferenceSize.height;
93+
attributes.frame = frame;
94+
95+
NSIndexPath *indexPath = [(UICollectionViewLayoutAttributes *)obj indexPath];
96+
BOOL isHeader = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionHeader];
97+
BOOL isFooter = [[obj representedElementKind] isEqualToString:UICollectionElementKindSectionFooter];
98+
99+
if (isHeader) {
100+
[headers setObject:obj forKey:@(indexPath.section)];
101+
} else if (isFooter) {
102+
// Not implemeneted
103+
} else {
104+
UICollectionViewLayoutAttributes *currentAttribute = [lastCells objectForKey:@(indexPath.section)];
105+
106+
// Get the bottom most cell of that section
107+
if ( ! currentAttribute || indexPath.row > currentAttribute.indexPath.row) {
108+
[lastCells setObject:obj forKey:@(indexPath.section)];
109+
}
110+
111+
if ([indexPath item] == 0 && [indexPath section] == 0) {
112+
visibleParallexHeader = YES;
113+
}
107114
}
108-
109-
if ([indexPath item] == 0 && [indexPath section] == 0) {
110-
visibleParallexHeader = YES;
115+
116+
if (isHeader) {
117+
attributes.zIndex = kHeaderZIndex;
118+
} else {
119+
// For iOS 7.0, the cell zIndex should be above sticky section header
120+
attributes.zIndex = 1;
111121
}
122+
}];
123+
124+
// when the visible rect is at top of the screen, make sure we see
125+
// the parallex header
126+
if (CGRectGetMinY(rect) <= 0) {
127+
visibleParallexHeader = YES;
112128
}
113-
114-
if (isHeader) {
115-
attributes.zIndex = kHeaderZIndex;
116-
} else {
117-
// For iOS 7.0, the cell zIndex should be above sticky section header
118-
attributes.zIndex = 1;
129+
130+
if (self.parallaxHeaderAlwaysOnTop == YES) {
131+
visibleParallexHeader = YES;
119132
}
120-
}];
121-
122-
// when the visible rect is at top of the screen, make sure we see
123-
// the parallex header
124-
if (CGRectGetMinY(rect) <= 0) {
125-
visibleParallexHeader = YES;
126-
}
127-
128-
if (self.parallaxHeaderAlwaysOnTop == YES) {
129-
visibleParallexHeader = YES;
130-
}
131-
132-
133-
// This method may not be explicitly defined, default to 1
134-
// https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewDataSource_protocol/Reference/Reference.html#jumpTo_6
135-
// NSUInteger numberOfSections = [self.collectionView.dataSource
136-
// respondsToSelector:@selector(numberOfSectionsInCollectionView:)]
137-
// ? [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView]
138-
// : 1;
139-
140-
// Create the attributes for the Parallex header
141-
if (visibleParallexHeader && ! CGSizeEqualToSize(CGSizeZero, self.parallaxHeaderReferenceSize)) {
142-
CSStickyHeaderFlowLayoutAttributes *currentAttribute = [CSStickyHeaderFlowLayoutAttributes layoutAttributesForSupplementaryViewOfKind:CSStickyHeaderParallaxHeader withIndexPath:[NSIndexPath indexPathWithIndex:0]];
143-
[self updateParallaxHeaderAttribute:currentAttribute];
144-
145-
[allItems addObject:currentAttribute];
146-
}
147-
148-
if ( ! self.disableStickyHeaders) {
149-
[lastCells enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
150-
NSIndexPath *indexPath = [obj indexPath];
151-
NSNumber *indexPathKey = @(indexPath.section);
152-
153-
UICollectionViewLayoutAttributes *header = headers[indexPathKey];
154-
// CollectionView automatically removes headers not in bounds
155-
if ( ! header) {
156-
header = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
157-
atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section]];
158-
133+
134+
135+
// This method may not be explicitly defined, default to 1
136+
// https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewDataSource_protocol/Reference/Reference.html#jumpTo_6
137+
// NSUInteger numberOfSections = [self.collectionView.dataSource
138+
// respondsToSelector:@selector(numberOfSectionsInCollectionView:)]
139+
// ? [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView]
140+
// : 1;
141+
142+
// Create the attributes for the Parallex header
143+
if (visibleParallexHeader && ! CGSizeEqualToSize(CGSizeZero, self.parallaxHeaderReferenceSize)) {
144+
CSStickyHeaderFlowLayoutAttributes *currentAttribute = [CSStickyHeaderFlowLayoutAttributes layoutAttributesForSupplementaryViewOfKind:CSStickyHeaderParallaxHeader withIndexPath:[NSIndexPath indexPathWithIndex:0]];
145+
[self updateParallaxHeaderAttribute:currentAttribute];
146+
147+
[allItems addObject:currentAttribute];
148+
}
149+
150+
if ( ! self.disableStickyHeaders) {
151+
[lastCells enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
152+
NSIndexPath *indexPath = [obj indexPath];
153+
NSNumber *indexPathKey = @(indexPath.section);
154+
155+
UICollectionViewLayoutAttributes *header = headers[indexPathKey];
156+
// CollectionView automatically removes headers not in bounds
157+
if ( ! header) {
158+
header = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
159+
atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section]];
160+
161+
if (!CGSizeEqualToSize(CGSizeZero, header.frame.size)) {
162+
[allItems addObject:header];
163+
}
164+
}
159165
if (!CGSizeEqualToSize(CGSizeZero, header.frame.size)) {
160-
[allItems addObject:header];
166+
[self updateHeaderAttributes:header lastCellAttributes:lastCells[indexPathKey]];
161167
}
162-
}
163-
if (!CGSizeEqualToSize(CGSizeZero, header.frame.size)) {
164-
[self updateHeaderAttributes:header lastCellAttributes:lastCells[indexPathKey]];
165-
}
166-
}];
168+
}];
169+
}
170+
171+
// For debugging purpose
172+
// [self debugLayoutAttributes:allItems];
173+
174+
return allItems;
175+
} else {
176+
return nil;
167177
}
168-
169-
// For debugging purpose
170-
// [self debugLayoutAttributes:allItems];
171-
172-
return allItems;
173178
}
174179

175180
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {

0 commit comments

Comments
 (0)