@@ -38,7 +38,10 @@ struct SectionModel {
3838 numberOfRows = 0
3939
4040 updateIndexOfFirstInvalidatedRowIfNecessary ( toProposedIndex: 0 )
41- calculateElementFramesIfNecessary ( )
41+
42+ if !MagazineLayout. _enableExperimentalOptimizations {
43+ calculateElementFramesIfNecessary ( )
44+ }
4245 }
4346
4447 // MARK: Internal
@@ -257,15 +260,22 @@ struct SectionModel {
257260 }
258261
259262 mutating func removeFooter( ) -> Bool {
260- guard let indexOfFooter = indexOfFooterRow ( ) else {
263+ guard footerModel != nil else {
261264 return false
262265 }
263- updateIndexOfFirstInvalidatedRowIfNecessary ( toProposedIndex: indexOfFooter)
266+ // `indexOfFooterRow()` is `nil` if the section hasn't been laid out yet (deferred layout
267+ // calculation). In that case the whole section is already invalidated from row 0, so there's no
268+ // additional row to invalidate.
269+ if let indexOfFooter = indexOfFooterRow ( ) {
270+ updateIndexOfFirstInvalidatedRowIfNecessary ( toProposedIndex: indexOfFooter)
271+ }
264272 footerModel = nil
265273 return true
266274 }
267275
268276 mutating func updateItemHeight( toPreferredHeight preferredHeight: CGFloat , atIndex index: Int ) {
277+ calculateElementFramesIfNecessary ( )
278+
269279 // Accessing this array using an unsafe, untyped (raw) pointer avoids expensive copy-on-writes
270280 // and Swift retain / release calls.
271281 itemModels. withUnsafeMutableBufferPointer { directlyMutableItemModels in
@@ -292,6 +302,8 @@ struct SectionModel {
292302 }
293303
294304 mutating func updateHeaderHeight( toPreferredHeight preferredHeight: CGFloat ) {
305+ calculateElementFramesIfNecessary ( )
306+
295307 headerModel? . preferredHeight = preferredHeight
296308
297309 if let indexOfHeaderRow = indexOfHeaderRow ( ) , let headerModel = headerModel {
@@ -312,6 +324,8 @@ struct SectionModel {
312324 }
313325
314326 mutating func updateFooterHeight( toPreferredHeight preferredHeight: CGFloat ) {
327+ calculateElementFramesIfNecessary ( )
328+
315329 footerModel? . preferredHeight = preferredHeight
316330
317331 if let indexOfFooterRow = indexOfFooterRow ( ) , let footerModel = footerModel {
@@ -393,7 +407,10 @@ struct SectionModel {
393407 }
394408
395409 private func indexOfFooterRow( ) -> Int ? {
396- guard footerModel != nil else { return nil }
410+ // `numberOfRows` is 0 until the section's element frames have been calculated. With deferred
411+ // layout calculation, the footer's row index isn't known yet in that state, so we return `nil`
412+ // rather than a bogus `numberOfRows - 1` (which would be -1).
413+ guard footerModel != nil , numberOfRows > 0 else { return nil }
397414 return numberOfRows - 1
398415 }
399416
0 commit comments