I have a UICollectionViewController
managing a collection view that uses different layouts for different app states. I'm using -setCollectionViewLayout:animated:
to transition between the different layouts. I'm having a bad access error, and it would help immensely to know what actually owns (e.g. keeps a strong
reference to) the collection view's current layout.
After calling -setCollectionViewLayout:animated:
, I've noticed the following (where self
is the UICollectionViewController
):
self.collectionView.collectionViewLayout
returns the new layout.self.collectionViewLayout
still returns the old layout.This led me to check the UICollectionView Class Reference, which explains this behavior:
collectionViewLayout
The layout object used to initialize the collection view controller. (read-only)
@property (nonatomic,readonly) UICollectionViewLayout *collectionViewLayout
Discussion
This property contains the layout object you passed to the initWithCollectionViewLayout: method. The layout object in this property is not updated to reflect changes to the collection view itself. You can use this property to refer to the layout object you originally configured the collection view to use.
Okay. So self.collectionViewLayout
is a weak reference (or is it?) to the initial layout and self.collectionView.collectionViewLayout
is a strong reference to the current layout.
To confirm this, I took a dive into the debugger, but wasn't able to find the actual UICollectionView
supposedly owned by the UICollectionViewController
. Instead, the collection view controller's _view
variable was an instance of UICollectionViewControllerWrapperView
. Whaaaat?
This whole experience left me with the following questions:
UICollectionView
stored in a UICollectionViewController
?self.collectionViewLayout
keep a strong
reference to the initial layout?This component allows for very simple grid layout creation and it even allows you to dynamically change layouts with beautiful animations. UICollectionView becomes even more powerful and flexible if you create your own layout by subclassing UICollectionViewLayout.
The first thing you should do is open up the Main.storyboard and drag a UICollectionView out to your View Controller. When you've done this give the collection view a white background color and add constraints to it so it will fit your view nicely.
Select the UICollectionView, hold ctrl and drag over to the code editor to create an outlet for the UICollectionView. I named mine "collectionView". That's all the setup we need for now. To display our cat images we need to have a UICollectionViewCell with an image inside of it.
When you've done this give the collection view a white background color and add constraints to it so it will fit your view nicely. If you're unsure how to do this, size the collection view so that it touches the left, bottom and right edges of the view and it should be aligned underneath the status bar.
Alright, I've already answered my first question: UICollectionViewControllerWrapperView
has an ivar called _subviewCache
, which is a mutable array containing the actual UICollectionView
at index 0. Weird.
However, I would still love an answer to my second question. It seems to me like the collection view controller is not keeping a strong reference to the initial layout because its collectionViewLayout
(initial layout) property is readonly, and I can't find any reference to a collection view layout when inspecting the collection view controller in the variables view of the debugger. Yet, if this is the case, how is it holding onto the initial layout even after the collection view's strong reference to the initial layout has been replaced with a strong reference to a different layout?
Update: It turns out the bad-access crash I was seeing was actually caused by a slightly different issue that has to do with UIDynamicAnimator
's ownership of the layout. This is almost definitely a bug in Apple's code, and I've filed a radar which you can read here (duplications welcome!):
http://www.openradar.me/15062440
That said, none of this technically addresses my second question. It's no longer relevant to me or to my work, but I'd still welcome and upvote any real answers, even if they'd be purely academic at this point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With