EthanHess / FiveTest

Social networking app using Parse and Alamofire
1 stars 1 forks source link

Layout attribute issues only when using Parse #1

Open tamez opened 9 years ago

tamez commented 9 years ago

When using dummy data, the circular collection view shows up and there are no errors with the custom layout, yet when Parse is queried the app crashes upon opening the collection view controller and the error reads "Assertion failure in -[UICollectionViewData validateLaoutInRect:] ... 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist:

Upon googling the error the suggestions were mostly to call "collectionView.invalidateLayout()" in the number of items method or in view did load/will appear but this did not work and it continues to throw a SIGABRT error. The collection view is in the EventCollectionViewController though the error gets thrown in the app delegate and putting a break point does nothing.

dingquan commented 9 years ago

do you have the full exception stack? if so, please paste it. if the code works with dummy data but not parse data. one possibility is that dummy data is available instantly while real data is fetched asynchronously. make sure the collections view cells are only rendered after data becomes available.

I see that the events data is fetched in EventCollectionViewController.viewWillAppear. But reloading of data is called in viewDidLoad(). Don't you want to reload data in the callback block of query.findObjectsInBackgroundWithBlock() ? right after the "self.events = objects" assignment. Otherwise, there's no code to trigger the collection to be re-rendered once the events data is fetched.

EthanHess commented 9 years ago

Ah okay, that probably has something to do with it. I tried this in view did load, both with and without the dispatch_async and it still threw the same error.

override func viewDidLoad() {
    super.viewDidLoad()

    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 30, left: 20, bottom: 30, right: 20)
    layout.itemSize = CGSize(width: self.view.frame.size.width / 2.5, height: 120)

    testEvents = ["homer","marge","bart","lisa","maggie"]
    testImages = ["homer", "marge", "bart", "lisa", "maggie"]

    dispatch_async(dispatch_get_main_queue(), { () -> Void in  
        let query = Event.query()

        query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in

            if let objects = objects as? [Event] {
                self.events = objects
            }
                else if let error = error {
                println("error: \(error.localizedDescription)")
            }             
        })

    })

 //        collectionView.collectionViewLayout.invalidateLayout()     
           collectionView.reloadData()        
    }

Here is the full error message...

2015-09-08 11:49:56.202 FiveTest[15072:861810] * Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-3347.44.2/UICollectionViewData.m:426 2015-09-08 11:49:56.208 FiveTest[15072:861810] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}' * First throw call stack: ( 0 CoreFoundation 0x0000000109c92c65 exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010b7fdbb7 objc_exception_throw + 45 2 CoreFoundation 0x0000000109c92aca +[NSException raise:format:arguments:] + 106 3 Foundation 0x000000010a12f98f -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195 4 UIKit 0x000000010ab9268b __45-[UICollectionViewData validateLayoutInRect:]_block_invoke + 1125 5 UIKit 0x000000010ab91d9d -[UICollectionViewData validateLayoutInRect:] + 3092 6 UIKit 0x000000010ab55850 -[UICollectionView layoutSubviews] + 194 7 UIKit 0x000000010a5b19eb -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 536 8 QuartzCore 0x0000000108f21ed2 -[CALayer layoutSublayers] + 146 9 QuartzCore 0x0000000108f166e6 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380 10 UIKit 0x000000010a5a5635 -[UIView(Hierarchy) layoutBelowIfNeeded] + 607 11 UIKit 0x000000010a69ff18 -[UITabBarController _layoutViewController:] + 500 12 UIKit 0x000000010a6a0026 -[UITabBarController _wrapperViewForViewController:] + 252 13 UIKit 0x000000010a6a7021 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 378 14 UIKit 0x000000010a6a31ba -[UITabBarController _setSelectedViewController:] + 311 15 UIKit 0x000000010a5a964e +[UIView(Animation) performWithoutAnimation:] + 65 16 UIKit 0x000000010a6a0118 -[UITabBarController _selectDefaultViewControllerIfNecessaryWithAppearanceTransitions:] + 221 17 UIKit 0x000000010a6a0e15 -[UITabBarController viewWillAppear:] + 121 18 UIKit 0x000000010a665f61 -[UIViewController _setViewAppearState:isAnimating:] + 487 19 UIKit 0x000000010a6928e1 -[UINavigationController _startTransition:fromViewController:toViewController:] + 793 20 UIKit 0x000000010a693408 -[UINavigationController _startDeferredTransitionIfNeeded:] + 523 21 UIKit 0x000000010a693ece -[UINavigationController viewWillLayoutSubviews] + 43 22 UIKit 0x000000010a7de6d5 -[UILayoutContainerView layoutSubviews] + 202 23 UIKit 0x000000010a5b19eb -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 536 24 QuartzCore 0x0000000108f21ed2 -[CALayer layoutSublayers] + 146 25 QuartzCore 0x0000000108f166e6 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380 26 QuartzCore 0x0000000108f16556 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24 27 QuartzCore 0x0000000108e8286e _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242 28 QuartzCore 0x0000000108e83a22 _ZN2CA11Transaction6commitEv + 462 29 QuartzCore 0x0000000108e840d3 _ZN2CA11Transaction17observer_callbackEP19CFRunLoopObservermPv + 89 30 CoreFoundation 0x0000000109bc5ca7 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION** + 23 31 CoreFoundation 0x0000000109bc5c00 CFRunLoopDoObservers + 368 32 CoreFoundation 0x0000000109bbba33 __CFRunLoopRun + 1123 33 CoreFoundation 0x0000000109bbb366 CFRunLoopRunSpecific + 470 34 GraphicsServices 0x000000010dd04a3e GSEventRunModal + 161 35 UIKit 0x000000010a5318c0 UIApplicationMain + 1282 36 FiveTest 0x00000001088ec007 main + 135 37 libdyld.dylib 0x000000010bf33145 start + 1 38 ??? 0x0000000000000001 0x0 + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

dingquan commented 9 years ago

don't put the query into dispatch_asyn. Query itself is async already. what I meant was to put the following in viewDidLoad()

    query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in

        if let objects = objects as? [Event] {
            self.events = objects
            collectionView.reloadData() 
        }
            else if let error = error {
            println("error: \(error.localizedDescription)")
        }             
    })

And get rid of viewWillAppear. Query doesn't need to be run every time the view appears.

EthanHess commented 9 years ago

Okay cool, I got rid of dispatch_async and put that closure right at the beginning of viewDidLoad but we're still getting the exact same error.

Perhaps it's reading the nonexistent events array in numberOfItemsInSection before the value of self.objects is determined?

dingquan commented 9 years ago
  1. put some logging or add break points to verify that the exception is happening before the query has a chance to finishing fetching the data (that's what i suspect)
  2. once 1 is confirmed, check anywhere you're messing with the layout to see why your code thinks there's at least one section/element in your collection view (as it is trying to access IndexPath (0-0) mentioned in the exception stack)

I don't have much experience with UICollectionViewLayoutAttributes but I see many places in your code assuming there's at least one element in the collection which is probably dangerous and wrong:

numberOfItemsInSection(0)

How can you be sure there is even a section 0? Actually, where's your numberOfSections() implementation in EventCollectionViewController?

That's as much as I can help.

EthanHess commented 9 years ago

I added the numberOfSections method and put return 1 but nothing changed.

I have figured out however, that it's crashing at the numberOfItemsInSection method

I want to try...

if let events = self.events {
  return events.count 
 }

But I'm not sure how to return it outside of the block.

No worries, thank you for your help!

dingquan commented 9 years ago

return events.count ?? 0