awakeFromNib() called twice in UICollectionViewCell subclass at scroll start - ios

I have custom UICollectionViewCell in xib. When ViewController is loaded - awakeFromNib() in cell subclass called 6 times (the screen initially placed 6 cells, ok), BUT when i start to scroll, awakeFromNib() is called six times more, causing lag. But after this "re-load" scrolling begins to work smoothly. This happens only the first time at scroll start. dequeueReusableCell, obviously, is used.With UITableView instead collection the situation is similar.
Feel like the next 6 cells are loaded from the xib again (in the collection of just 100+ cells), ignoring reuse. What could be the problem?
For clarity:
UIColectionView with Vertical scroll direction, two cells in line. When ViewController loaded i see 6 cells on screen and 6 awakeFromNib calls in console.
I start scroll down to 7-8 cells, before their appearance on the screen i see lag and 2 calls of awakeFromNib method.
Similarly for the following two pairs of cells.
After this scroll begins work fine, until cells 99-100+, and awakeFromNib is never invoked.
Added:
OK, here's what I found out:
I have a subView inside a collectionView (header like in UITableView), and, accordingly, collectionViewLayout set sectionInsets top = height of header. If I remove the header, and make the top insets, for example: -180 (about excluding the height of NavigationBar, so the screen initially fit 12 cells and the scroll lag is gone.
Ie, the system needs to load from the xib at all the cells that will be one-time visible on the screen and reuse them in future. (But why not one time load xib and reuse it immediately for all other initially cells?)
And now the question - how to fix it?
Added.2
Working solution - add header in viewDidAppear method of ViewController, but this... hm.. not good.

This is actually a known side effect (or purposeful design?) of UICollectionView & UITableView. Here's a related question (talking about NSTableView, but the concepts/issues are the same):
awakeFromNib method called multiple times
Your collection view initially displays six cells to start with, but it sounds like iOS is allocating six more cells to allow for scrolling left & right. So there are at least 12 (reuseable) cells in memory.
If you're doing a lot of work in awakeFromNib (which is what's contributing to the lag), you might want to try to determine how to optimize things.
You can also find some additional helpful hints in this related question:
UITableViewCell - Best place to set up the cell

Related

Dynamic cell height issue with UITableViewCell autolayout jerk while scrolling

I am trying to do something like loading up different type of cells with custom height in a uitableview. The tableview cells are subclassed and consists of labels with the respective constraints. Each cell is having a dynamic height.
Now even before my table reloads the data, I am calculating the height that is required for the resizing of the cells and caching it in my model class so that I dont have to calculate the height when the data is rendered on the device.
To calculate height i did use the tutorial from Ray Wenderlich and I am having the right set of heights applies to the objects.
Now the problem comes. Whenever I am dequeueing the cells there is a
kind of a small jerk that gives me an indication that my cell is
dequeued while scrolling.
How can i make these movement smooth so that there is no jerk while scrolling the view ?
The height is getting assigned in and does get the value as per the current type of data getting loaded.
estimatedRowForIndexPath
Also I am calling layoutIfNeeded from my cellForAtindexPath
Suggestions are most welcome.
It's very hard to say without seeing your code in cellForRowAtIndexPath, and without seeing your cells and their respective code. Here are some general questions I would investigate:
What is the content of the cells and how complex is the view hierarchy in the cell?
Even though you are supplying the correct estimated height, an autolayout pass still needs to happen, and a complex view hierarchy will take time to resolve
Does the cell contain images?
Images that need to be decompressed from a file (UIImage imageNamed:) can be intensive and cause scrolling issues, check images are not bigger than they need to be. If needed, bump this work onto a background thread.
Are you calling a complex method to configure the cell for display in cellForRowAtIndexPath?
Look at the work actually being done in cellForRowAtIndexPath, is there a complex method being triggered in you cell subclass or view model?
Are you adding and removing views to the cell view hierarchy in cellForRowAtIndexPath?
If views are being added, removed, created, inflated from a xib, constrained etc during the cell config, this could slow things down. Try to do only what is strictly needed. Check if there is any code being run internally in the cell subclass during cellForRowAtIndexPath that could be moved to cells initWith... or awakeFromNib methods (ie code that could just run once when the cell is created, rather than every time the cell is displayed)
Also run the Instruments time profiler, see if that offers any more clues

Two UIViews & one UICollectionView inside UIScrollView (or better approach)

I need to have iOS app with screen like this:
screen
The idea is when user start to scroll down the first UIView to move up until the second UIView reach the top where it will stick and only UICollectionView will continue to move up.
Currently I'm using this structure
UIScrollView (main scroll)
UIView (some banners)
UIView (UISegmentedControl)
UICollectionView (grid with items, scroll is disabled, main scroll is used)
I manage to do it, but I needed to set UICollectionView height constraint manually in the code (calculated based on all items in grid) in order to appear in UIScrollView (everything else is handled by AutoLayout in Storyboard). The problem with this is that UICollectionView think all cells are visible and load them, so the whole recycling & reusing thing does not work. It's even worst because I use willDisplayCell method on UICollectionView to load more data when last cell is displayed, but now it load all pages at once.
My question (actually they are 2)
How can I fix the issue above?
What is the right way to achieve this functionality? Maybe my whole approach is conceptually wrong?
Collection view is a scroll view itself. So maybe you could have same functionality only with Collection view with sections or even custom layout?

Re-Enabling dequeuing on a UICollectionView within a UIScrollView

I'm trying to set up a particularly large UICollectionView, and I'm embedding it within a UIScrollView (as per this answer to another question on SO) in order to support scrolling in both directions. I've got it up and running, everything is working perfectly, except that performance takes a HUGE hit as the size of the CollectionView grows.
After some hunting around, I was able to figure out the problem: because that SO answer calls for the CollectionView to be resized so that all the cells are visible at once, "dequeuing" isn't a thing anymore. The CollectionView within the ScrollView has dimensions of 2000x2000 (or whatever), so even though the ScrollView is just the size of the screen and only shows 20 cells or so at a time, the CollectionView thinks all cells are visible and needed right now. Thus, every cell in the CollectionView is generated at once, meaning the page takes a ludicrously long time to appear.
Is there a way to communicate to the CollectionView which cells are currently visible through the ScrollView, so it doesn't generate unnecessary cells and dequeues them as normal? Or if not, is there a way to make a CollectionView that scrolls diagonally, but that doesn't have this problem?

UICollectionView cell layout is out of the collection view's bounds

I have a UICollectionView which lays its cells out using Flow Layout. It is vertically scrolling.
It fills a 320x480 screen and displays a custom UICollectionViewCell which is always 96*96 - the size is set in Interface Builder and the delegate does not implement methods to set the item size on a per item basis.
There are insets on the left and right which are 10 px each and the minimum spacing is set to 6px.
What happens therefore is 3 cells per horizontal line.
<-10-><----96----><-6-><----96----><-6-><----96----><-10-> = 320.
The problem that I am having is that occasionally it lays 4 cells on one line!
The 4th cell is mostly off the screen. It then lays only 2 cells out on the following line to compensate. The whole point of flow layout is that it is a line-breaking layout which should not put anything off-screen!
I have attached a picture:
Please note that on the second row there is a fourth item mostly off the screen.
I really have no idea what could be causing it. The cells are dynamically filled with data but their size is constant. The cells on all other rows are fitting just fine so there is no reason why on some rows this should happen.
This error occurs at different places each time the collection view is updated. ie. it might happen at row 2 then once an update happens it might happen at row 10 and so on.
The collection view is being updated by a timer. The timer essentially calls a function which processes some data, and then using dispatch_async (onto the main queue) an array containing the backing data is updated and [collectionView reloadData] is called. So I haven't updated the collection view from any thread apart from the main thread. The backing array is only updated on the main queue and in that function; not from anywhere else.
Please could someone give me some suggestions as to what might be going wrong.
Thanks
I have fixed it by adding [_collectionViewFlowLayout invalidateLayout] in scrollViewDidScroll: delegate methods.
https://github.com/f33chobits/FSCalendar/issues/21

UITableView will not resize after UITextField becomes first responder

I have two Scenes in my Storyboard that are nearly identical. Both are UITableViewControllers. Both have header and footer views. The header views have a UISearchBar and the footer views have a UIView that contains a UITextField. Each have only one prototype cell. One is prototyped as a "Basic" cell and the other is prototyped as "Right Detail" cell.
Here's the problem. When I click the UITextField in the footer view on the first scene, the table resizes automatically so that the bottom of the table is at the top of the keyboard. This allows me to scroll the table up so the footer view shows and the user is able to see what they're typing. The other scene will not automatically resize the UITableView so the UITableView cannot scroll the footer view to where it can be seen and the UITextField is hidden under the keyboard. I can't even manually scroll the table far enough since the footer is always at the bottom of the UITableView.
A little added info. The scene that works has many rows of data while the one that doesn't work only has a couple. I tried adding a number of rows until the table had enough to enable scrolling and it doesn't fix the problem.
I have checked everything I can think of and I can't see anything that would allow one of the views to let the UITableView to automatically resize to work with the keyboard and the other not. I must have overlooked something but I can't seem to find it.
Any help will be greatly appreciated!
Rob
I thought this problem was caused by copy-and-pasting from one view to another, but I had the same problem once I'd (in theory) fixed it.
The answer for me turned out to be simple: I hadn't called [super viewWillAppear:animated] in my UITableViewController subclass' viewWillAppear: implementation. Make sure you've got a call to the superclass' method and hopefully the problem will go away.
I am guessing the frame of the tableview is not being resized to the smaller size in the second case.
Print out the frame and content sizes in both the cases once its loaded, that should help you see if there is an issue.

Resources