Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UiviewControllers inside UICollectionViewCell

I have a UICollectionView inside a UIViewController. The collectionView holds an array of 8 identifiers of view controllers from the storyboard. Each view controller in the array inherited from the UIViewController that holds the collectionView.

Here is the code:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _contentPageRestorationIDs.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];

BaseContentViewController *contentViewController = (BaseContentViewController *)[self.storyboard instantiateViewControllerWithIdentifier:self.contentPageRestorationIDs[indexPath.row]];

// Set any data needed by the VC here
contentViewController.rootViewController = self;
contentViewController.view.frame = cell.bounds;
[cell addSubview:contentViewController.view];

return cell;
}

So my problem is that my collection view swipe performance is really slow. How can i improve the UICollectionView's performance? Are my view controllers inside the cell are "killed" when they are not on display?

Edit:

after the advice here i have changed my array to holding a view controllers instead of identifiers nsstring.

In the ViewDidLoad:

_collectionView.delegate=self;
_collectionView.dataSource=self;
PRzeroVC  *zeroVC    = [[PRzeroVC alloc]init];
PRoneVC   *oneVC     = [[PRoneVC alloc]init];
PRtwoVC   *twoVC     = [[PRtwoVC alloc]init];
PRthreeVC *threeVC   = [[PRthreeVC alloc]init];
PRfourVC  *fourVC    = [[PRfourVC alloc]init];
PRfiveVC  *fiveVC    = [[PRfiveVC alloc]init];

_base           = [[BaseContentViewController alloc]init];

_pages = [[NSArray alloc]initWithObjects:zeroVC,oneVC,twoVC,threeVC,fourVC,fiveVC, nil];

[_collectionView reloadData];



- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = (UICollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];

cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
_base = (BaseContentViewController *)_pages[indexPath.row];

_base.rootViewController = self;
_base.view.frame = cell.bounds;
[cell addSubview:_base.view];

return cell;
}

My cell is not displaying the view Any idea why?

like image 691
Gili Ariel Avatar asked Feb 10 '23 01:02

Gili Ariel


2 Answers

I was able to obtain smooth-scrolling performance of a collection of cells containing each its own child view controller by using a queue to keep and reuse a set number of instances.

GitHub lists a number of reuse queue implementations; and, after a fairly thorough review of almost every one if them, I can confidently recommend this one:

https://github.com/acoomans/ACReuseQueue

Per the ReadMe: A reuse queue is a way to quickly reuse objects when object allocation and initialization is time-consuming.

The reason your view is not showing is because you're not instantiating the child view controller from within the cell subclass, and not adding the view from within the cellForItemAtIndexPath. It's about scope, and you've got it backwards.

The perfect set of instructions for adding a child view controllers to cells is provided here:

http://khanlou.com/2015/04/view-controllers-in-cells/

like image 160
James Bush Avatar answered Feb 24 '23 16:02

James Bush


From the documentation of instantiateViewControllerWithIdentifier: -

This method creates a new instance of the specified view controller each time you call it

You would be better to store an array of UIViewControllers so they can be re-used, rather than storing the IDs and instantiating a new view controller every time tableView:cellForItemAtIndexPath: is called.

Also, since UICollectionViewCells are re-used, it's not wise to keep adding subviews to the cell every time tableView:cellForItemAtIndexPath: is called. Instead, consider creating your own UICollectionViewCell subclass with a mainView property. You could override setMainView: to remove the old mainView from its superview, before setting the new one's frame (or adding layout constraints) and adding it as a subview.

Also you should implement the methods for proper UIViewController containment.

like image 20
johnpatrickmorgan Avatar answered Feb 24 '23 17:02

johnpatrickmorgan