load UICollectionViewCell to UIView - ios

Im trying to load UICollectionViewCell from .xib, to the UICollectionView, which is in reusable UIView also in .xib. This UIView will be loaded to more UIViewControllers. I found out, that I need load cell like this:
[self.collectionView registerNib:[UINib nibWithNibName:#"MyCell" bundle:nil] forCellWithReuseIdentifier:#"CELL"];
but it will not load it.
I looked all around net for answer, but I couldn't find this specific case.

There are two different cases,
1) If you're using storyboards and custom cells.
2) Nib and simple UIView(hierarchy of UIViews).
Yours seems to be the second case,
First of all you need to make instance of a UICollectionView(by alloc init methods).
Then register the Nib holding your cell/view using following method.
[self.collectionView registerNib:[UINib nibWithNibName:CELL_IDENTIFIER bundle:nil] forCellWithReuseIdentifier:CELL_IDENTIFIER];
and then you can use that Nib using following method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell;
cell = (UICollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER
forIndexPath:indexPath];
//Populate your data here.
return cell;
}
Hope this helps.. :)

Related

UICollectionView don't reuse cell on ios 8 and ipad air 1

I'm not using storyboard, everything is done by code..
and when I scroll the UICollectionView.. after it reusing correctly..some cells..
than it happen :
-the cell initWithFrame is being call
-new gray hair appear on my head.
I read other q/a and check maybe it's something with threads but all the reloadData is on the main thread.
any directions ?
I have no idea what's your code, so I'll propose how do I do it:
// somewhere in eg viewDidLoad
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellId];
And later the delegate:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = cell = [collectionView dequeueReusableCellWithReuseIdentifier:MyCellId forIndexPath:indexPath];
// do something with your cell, set title or anything
return cell;
}
There is another possibility. Your cell, as it's reusable, will have already saved previous properties. So if you did something like this:
if (iCanAddGrayHair) {
[cell.imageView setImage:[UIImage imageNamed:#"hair"]]
}
Then do notice, that new cell will still have this image set! You need to add:
else {
[cell.imageView setImage:nil];
}
To reset it from previous state. You can also override prepareForReuse: method of UICollectionViewCell class to reset the values (don't forget to call super).

UICollectionView with UITextView very slow

I have a UICollectionView, with custom UICollectionViewCell.
Every cell has a UITextView inside.
The problem: the UICollectionView is very slow, also in the simulator.
-(void)viewDidLoad
{
[self.collectionView registerClass:[AgendaCollectionCell class]
forCellWithReuseIdentifier:agendaCellIdentifier];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
AgendaCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:agendaCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
[cell setCurrentDateAtIndex:([indexPath row]) date:currentMonth events:events];
// Return the cell
return cell;
}
I checked the profiler
Every cell makes date-related computations.
As you can see, the loadNibNamed takes too much time to load. Also the UITextView takes too much.
I searched a lot of question here and used some of their answers.(I also cached all instances of NSCalendar). I do not understand why it takes about 435 ms to load. The UICollectionView has 40 cell (it contains the days of a month).
Should I abandon the use of UICollectionView and cast to a custom view by using drawRect?
EDIT
I think that a good point is that suggested in the answer: load the cell by using UNib and not registerClass. I can see a very big performance boost: from 400ms to just 98ms!
Try putting
UINib * nib = [UINib nibWithNibName:#"YourNibName" bundle:[NSBundle mainBundle]];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:#"MyCell"];
into your viewDidLoad and then never create the cells yourself (in the
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForIndexPath:(NSIndexPath *)indexPath;
implementation always call
UICollectionViewCell * cell = [collectionView dequeueCell...]
This way, I think, the collection view will only load the nib once (in your viewDidLoad method and then create copies of it when needed.

Custom Layout for custom cell design on UICollectionViewController

I want to design a page like this image for Ipad:
I decide to implement it by UICollectionViewController, and I am going to use UICollectionViewController for the first time.
I want to know, UICollectionViewController let me have various layout for cells? and how can I do that?
Yes you can have different layouts for cells.
In your UICollectionView, you will need to register the various cell classes that you are going to use:
[self registerClass:[Class1 class] forCellWithReuseIdentifier:#"Class1"];
[self registerClass:[Class2 class] forCellWithReuseIdentifier:#"Class2"];
Then in your datasource delegate:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//Whatever logic you will use to distinguish between the two classes
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Class1" forIndexPath:indexPath];
//OR
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Class2" forIndexPath:indexPath];

Why am I getting a deallocated memory call when I call UICollectionViewCell dequeueReusableCellWithReuseIdentifier?

I have a UICollectionView that contains custom UICollectionViewCells (TestReceiptCell is the class name).
I was not having any problems getting the UICollectionView to appear and load the custom cells when the custom cells only contained a UILabel.
I then added a UITableView via IB into the TestReceiptCell NIB file. I set a referencing outlet in TestReceiptCell.h for the UITableView and synthesized in the .m file. I set the delegate and datasource for the UITableView to the ViewController containing the UICollectionView.
Now when running the app I get a EXC_ BAD_ ACCESS exception in this block on the third line:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"TestReceiptCell";
TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; //exception thrown here
return cell;
}
I ran the Zombie Instrument test and found that the deallocated memory call originates here. This is my first time using that instrument so I am not exactly sure how to investigate from here.
For reference, here are some more relevant parts of the code:
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.myCollectionView registerNib:[UINib nibWithNibName:#"TestReceiptCell" bundle:nil] forCellWithReuseIdentifier:#"TestReceiptCell"];
// Setup flowlayout
myCollectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[myCollectionViewFlowLayout setItemSize:CGSizeMake(310, 410)];
[myCollectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.myCollectionView setCollectionViewLayout:myCollectionViewFlowLayout];
self.myCollectionView.pagingEnabled = YES;
}
I am implementing the UITableView datasource and delegate methods in the ViewController.m file as well but I am not sure if the problem lies here given the origination of the EXC_BAD_ACCESS exception:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"eventCell"];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"eventCell"];
}
return cell;
}
UPDATE:
I am able to get this to run if I change cellForItemAtIndexPath to:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"TestReceiptCell";
//TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
TestReceiptCell *cell = [NSBundle.mainBundle loadNibNamed:#"TestReceiptCell" owner:self options:nil][0];
return cell;
}
However, I am not dequeuing cells and know this is not the correct way. There seems to be an issue somewhere in the initWithFrame method that gets called when dequeueReusableCellWithResueIdentifier creates a new cell. Here is that method currently:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:#"TestReceiptCell" owner:self options:nil];
if ([arrayOfViews count] < 1) {
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
EDIT:
If I do not select a delegate or a datasource for the tableview, the collectionview with tableviews will load. Something in attaching the delegate/datasource to File's Owner is causing the error.
When you register a UINib for cell reuse, dequeueReusableCellWithReuseIdentifier:forIndexPath: is what calls instantiateWithOwner:options: on the UINib that you registered. Whatever it passes for owner, is what becomes the File's Owner outlet in your nib.
It appears that you are expecting the File's Owner to be the UICollectionView, but I don't think that it is.
Even if it were, I don't think you should use the UICollectionView for the delegate of the UITableView contained within each collection cell. That would require your UICollectionView to keep track of the tableViews and contents within each cell.
I'd suggest setting the delegate of the contained tableView to the collection cell itself and have each cell manage its own tableview.
EDIT:
You can define a delegate protocol for your collection view cells to communicate the relevant table view events to the collection view. With this approach, you would set the delegate property you define for each collection cell in the collectionView:cellForItemAtIndexPath method of your collection view datasource.
When the user, for example, selects an item from the table, you can call the cell delegate to inform the collection view which item was selected.
This approach allows you to abstract the fact that your collection cell is using a table view to display the cell information. Later, if you decide you want to use, for example, an embedded UICollectionView to display those items, the delegate protocol can remain unchanged and you can isolate your changes to the collection cell.

How to use UINib to instantiate and use custom UITableViewCells

how would i use UINibs to instantiate and use a UITableViewCell for a tableview in iOS5.0. I know there is a registerNib:forCellReuseIdentifier: in iOS5.0 that also needs to be used, but am not sure how to use it
Thanks in advance for any help on this
Create your xib file with a UITableViewCell as the top-level object. This is called Cell.xib
Create a UINib object based on this file
Register the UINib with the table view (typically in viewDidLoad of your table view controller subclass).
Steps 2 and 3 can be combined, so you would use the following line in viewDidLoad:
[self.tableView registerNib:[UINib nibWithNibName:#"Cell" bundle:nil] forCellReuseIdentifier:#"Cell"];
Then, in cellForRowAtIndexPath, if you want one of the cells from the nib, you dequeue it:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
This either creates a new instance from the nib, or dequeues an existing cell.
#jrturtons answer is correct but unfortunately there's a bug in iOS 5 (fixed in iOS 6) in conjunction with VoiceOver: rdar://11549999. The following category on UITableView fixes the issue. Just use -fixedDequeueReusableCellWithIdentifier: instead of the normal dequeueReusableCellWithIdentifier:. Of course, the NIB must be registered using
[self.tableView registerNib:[UINib nibWithNibName:#"Cell" bundle:nil] forCellReuseIdentifier:#"Cell"];
before (in -viewDidLoad).
UITableView+Workaround.m:
#implementation UITableView (Workaround)
- (id)fixedDequeueReusableCellWithIdentifier:(NSString *)identifier {
id cell = [self dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
// fix for rdar://11549999 (registerNib… fails on iOS 5 if VoiceOver is enabled)
cell = [[[NSBundle mainBundle] loadNibNamed:identifier owner:self options:nil] objectAtIndex:0];
}
return cell;
}
#end

Resources