Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'No UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath' error using custom UICollectionViewLayout

I'm using a custom UICollectionViewLayout like this :

override func prepareLayout() {
        cache.removeAll(keepCapacity: false)

        let standardHeight = LayoutConstants.Cell.standardHeight
        let featuredHeight = LayoutConstants.Cell.featuredHeight

        var frame = CGRectZero
        var y: CGFloat = 0

        for item in 0..<numberOfItems {
            let indexPath = NSIndexPath(forItem: item, inSection: 0)
            let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
            let cell = collectionView!.cellForItemAtIndexPath(indexPath)
            /* Important because each cell has to slide over the top of the previous one */
            attributes.zIndex = item
            /* Initially set the height of the cell to the standard height */
            var height = standardHeight
            if indexPath.item == featuredItemIndex {
                /* The featured cell */
                let yOffset = standardHeight * nextItemPercentageOffset
                y = collectionView!.contentOffset.y - yOffset
                height = featuredHeight
            } else if indexPath.item == (featuredItemIndex + 1) && indexPath.item != numberOfItems {
                /* The cell directly below the featured cell, which grows as the user scrolls */
                let maxY = y + standardHeight
                height = standardHeight + max((featuredHeight - standardHeight) * nextItemPercentageOffset, 0)
                y = maxY - height
            }
            frame = CGRect(x: 0, y: y, width: width, height: height)
            attributes.frame = frame
            cache.append(attributes)
            y = CGRectGetMaxY(frame)
        }
    }

    /* Return all attributes in the cache whose frame intersects with the rect passed to the method */
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
        var layoutAttributes = [UICollectionViewLayoutAttributes]()
        for attributes in cache {
            if CGRectIntersectsRect(attributes.frame, rect) {
                layoutAttributes.append(attributes)
            }
        }
        return layoutAttributes
    }

That's works as I want but if I wanna insert an other item, my app crash with this error :

2015-05-31 22:37:29.032 Flore-Jessy[15359:717220] *** Assertion failure in -[UICollectionViewData layoutAttributesForItemAtIndexPath:], /SourceCache/UIKit_Sim/UIKit-3347.44/UICollectionViewData.m:694
2015-05-31 22:37:29.077 Flore-Jessy[15359:717220] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0x7b952a70> {length = 2, path = 0 - 15}'
*** First throw call stack:
(
    0   CoreFoundation                      0x00a0a746 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x02867a97 objc_exception_throw + 44
    2   CoreFoundation                      0x00a0a5da +[NSException raise:format:arguments:] + 138
    3   Foundation                          0x01093720 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
    4   UIKit                               0x01de5c74 -[UICollectionViewData layoutAttributesForItemAtIndexPath:] + 461
    5   UIKit                               0x01dafbe7 __51-[UICollectionView _viewAnimationsForCurrentUpdate]_block_invoke1382 + 161
    6   UIKit                               0x01dad73b -[UICollectionView _viewAnimationsForCurrentUpdate] + 4789
    7   UIKit                               0x01db0eb8 -[UICollectionView _updateWithItems:tentativelyForReordering:] + 2447
    8   UIKit                               0x01dabf0d -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:] + 14802
    9   UIKit                               0x01da8536 -[UICollectionView _endItemAnimationsWithInvalidationContext:] + 48
    10  UIKit                               0x01da82ed -[UICollectionView _updateRowsAtIndexPaths:updateAction:] + 374
    11  UIKit                               0x01da833f -[UICollectionView insertItemsAtIndexPaths:] + 48
    12  Flore-Jessy                         0x0009183c _TFC11Flore_Jessy22TimelineViewController13viewDidAppearfS0_FSbT_ + 556
    13  Flore-Jessy                         0x000918cf _TToFC11Flore_Jessy22TimelineViewController13viewDidAppearfS0_FSbT_ + 63
    14  UIKit                               0x017f3245 -[UIViewController _setViewAppearState:isAnimating:] + 629
    15  UIKit                               0x017f3860 -[UIViewController __viewDidAppear:] + 171
    16  UIKit                               0x017f3b2b -[UIViewController _endAppearanceTransition:] + 322
    17  UIKit                               0x0180bd4e -[UIViewController(UIContainerViewControllerProtectedMethods) endAppearanceTransition] + 41
    18  UIKit                               0x017c403b -[UIPresentationController transitionDidFinish:] + 839
    19  UIKit                               0x01e50109 -[_UIFullscreenPresentationController transitionDidFinish:] + 59
    20  UIKit                               0x017c6c11 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke_2 + 165
    21  UIKit                               0x01ef444a -[_UIViewControllerTransitionContext completeTransition:] + 124
    22  Flore-Jessy                         0x0008e174 _TFFC11Flore_Jessy29SwipeBluredTransitionAnimator17animateTransitionFS0_FPSo36UIViewControllerContextTransitioning_T_U0_FSbT_ + 436
    23  Flore-Jessy                         0x0008ca34 _TPA__TFFC11Flore_Jessy29SwipeBluredTransitionAnimator17animateTransitionFS0_FPSo36UIViewControllerContextTransitioning_T_U0_FSbT_ + 68
    24  Flore-Jessy                         0x0008e1bc _TTRXFo_dSb_dT__XFo_iSb_iT__ + 28
    25  Flore-Jessy                         0x0008caea _TPA__TTRXFo_dSb_dT__XFo_iSb_iT__ + 90
    26  Flore-Jessy                         0x0008e1f7 _TTRXFo_iSb_iT__XFo_dSb_dT__ + 39
    27  Flore-Jessy                         0x0008cb9e _TPA__TTRXFo_iSb_iT__XFo_dSb_dT__ + 78
    28  Flore-Jessy                         0x0008e245 _TTRXFo_dSb_dT__XFdCb_dV10ObjectiveC8ObjCBool_dT__ + 69
    29  UIKit                               0x017149be -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 318
    30  UIKit                               0x016f81b2 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 206
    31  UIKit                               0x016f8522 -[UIViewAnimationState animationDidStop:finished:] + 80
    32  QuartzCore                          0x0154a571 _ZN2CA5Layer23run_animation_callbacksEPv + 307
    33  libdispatch.dylib                   0x02f59bef _dispatch_client_callout + 14
    34  libdispatch.dylib                   0x02f3f6bb _dispatch_main_queue_callback_4CF + 993
    35  CoreFoundation                      0x009638ee __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
    36  CoreFoundation                      0x009215f0 __CFRunLoopRun + 2256
    37  CoreFoundation                      0x00920a5b CFRunLoopRunSpecific + 443
    38  CoreFoundation                      0x0092088b CFRunLoopRunInMode + 123
    39  GraphicsServices                    0x051e02c9 GSEventRunModal + 192
    40  GraphicsServices                    0x051e0106 GSEventRun + 104
    41  UIKit                               0x0168a106 UIApplicationMain + 1526
    42  Flore-Jessy                         0x00080a24 main + 180
    43  libdyld.dylib                       0x02f84ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

This is the code I use to insert the new item

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        if let post = newPost {

collectionView!.insertItemsAtIndexPaths([dataSource.indexPathForNewPost(post)])
        }
    }

/// Return the new indexPath for the TimelineItem
    func indexPathForNewPost(item: TimelineItem) -> NSIndexPath {
        if let liste = listPosts {
            listPosts!.append(item)
        }
        return indexPathForPost(item)
    }

    func indexPathForPost(item: TimelineItem) -> NSIndexPath {
        var itemIndex = 0
        for (index, currentTimelineItem) in enumerate(allPosts()) {
            if currentTimelineItem === item {
                itemIndex = index
                break
            }
        }
        return NSIndexPath(forItem: itemIndex, inSection: 0)
    }

Any idea ?

like image 288
Kevin Machado Avatar asked May 31 '15 20:05

Kevin Machado


1 Answers

Base on the error message, this is because of the cell can't retrieve layoutAttributes. layoutAttributesForItemAtIndexPath returns nil if cell which will be created by update is not visible.

To fix this error, override layoutAttributesForItemAtIndexPath method:

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
        return cache[indexPath.row]
    }

SWIFT 3 -

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cache[indexPath.row]
  }
like image 89
TomSawyer Avatar answered Nov 06 '22 04:11

TomSawyer