jboisjoli
jboisjoli

Reputation: 101

layoutAttributesForElementsInRect Swift 3 (UICollectionView)

this code used to work in swift 2.3 and earlier. But when i updated it in Swift 3, app is crashing.

This is the code in swift 2.3

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
    var layoutAttributes  = [UICollectionViewLayoutAttributes]()
    layoutInfo?.enumerateKeysAndObjectsUsingBlock({ (object: AnyObject, elementInfo: AnyObject, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
        let infoDic = elementInfo as! NSDictionary as NSDictionary!
        infoDic.enumerateKeysAndObjectsUsingBlock( { (object: AnyObject!, attributes: AnyObject!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
            let attr = attributes as! UICollectionViewLayoutAttributes
            if (CGRectIntersectsRect(rect, attributes.frame))
            {
                layoutAttributes.append(attr)
            }

        })
    })

    return layoutAttributes
}

this is the updated version by Swift 3

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    var layoutAttributes  = [UICollectionViewLayoutAttributes]()
    layoutInfo?.enumerateKeysAndObjects({ (object: AnyObject, elementInfo: AnyObject, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
        let infoDic = elementInfo as! NSDictionary as NSDictionary!
        infoDic?.enumerateKeysAndObjects( { (object: AnyObject!, attributes: AnyObject!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in

            let attr = attributes as! UICollectionViewLayoutAttributes
            if (rect.intersects(attributes.frame))
            {
                layoutAttributes.append(attr)
            }

        } as! (Any, Any, UnsafeMutablePointer<ObjCBool>) -> Void)
    } as! (Any, Any, UnsafeMutablePointer<ObjCBool>) -> Void)

    return layoutAttributes
}

I'm getting this crash at } as! (Any, Any, UnsafeMutablePointer) -> Void) EXC_BREAKPOINT

Anyone can help me?

This is the project i took from this guy. https://github.com/CoderXpert/EPGGrid

Upvotes: 1

Views: 4701

Answers (1)

Marcus
Marcus

Reputation: 2321

I think you have managed somehow to tie yourself up in knots with this topic. (It is always a warning sign to me if I end up using lots of casting and ObjectiveC types in what is supposed to Swift code). I just had a look at the implementation of layoutAttributesForElements(in) in one of my apps, and it boils down to the following:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    var layoutAttributes = [UICollectionViewLayoutAttributes]()
    if cache.isEmpty {
        self.prepare()
    }
    for attributes in cache {
        if attributes.frame.intersects(rect) {
            layoutAttributes.append(self.layoutAttributesForItem(at: attributes.indexPath)!)
        }
    }
    return layoutAttributes
}

In this implementation, cache is the array of UICollectionViewLayoutAttributes that is prepared when the collection view is initialised or the data changes (via the prepare() method). After ensuring that the cache is non-empty, all you need to do is iterate through the cache and collect any attributes whose frame intersects the frame in question. If an attribute is caught, use the method layoutAttributesForItemAt (another essential function if you are subclassing a layout manager) to pull in the required values.

While it is difficult to see exactly what is going on in your code, I think the problem is that layoutInfo and infoDic are structured in a way that is not appropriate to the task at hand (are they dictionaries?), hence the coding gymnastics to try and get a result! Anyway, hope that helps.

Upvotes: 1

Related Questions