UICollectionView cellForItemAtIndexPath not registering cell - objective-c

I am trying to use UICollectionViewCell, since all I want to display is an image. I can add the image to the cell using UIColor colorWithImage: on the UICollectionViewCell's contentView property.
In my loadView method, I am registering the cell as follows:
[self.collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:#"MyCell"];
Below is my cellForItemAtIndexPath method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
// cell customization
return cell;
}
When I run it, as soon as it hits the dequeue line, it crashes with the following error:
*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:]
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier MyCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
I tired setting up a custom cell, and used it as the class and I got the same error. My custom cell subclassed UICollectionViewCell and had nothing implemented, except for the default initWithFrame. That is because I wanted to just change the background colour of the view. I am not sure what the problem is but could someone please take a look at my code and help me? I've been trying to figure this out for quite a while with absolutely no luck at all.

If you just want to display an image, you don't need to do any subclassing, you can set the cell's backgroundColor with colorWithPatternImage:. Register the class like this:
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
Then use it like so:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithPatternImage:[self.results objectAtIndex:indexPath.row]];
return cell;
}
In this example, results is an array of UIImages.

If you are using xib in applivation then add following in your viewdidLoad method
[self.myCollectionView registerNib:[UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"CellIdentifier"];
otherwise If you using storyboard add following
[self.myCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"CellIdentifier"];
Finally add this (If not)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CellIdentifier" forIndexPath:indexPath];
return cell;
}
Hope above will help.

Try setting a breakpoint on
[self.collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:#"MyCell"];
I would guess your loadView (did you mean viewDidLoad?) method is not being called, so the class is never registered with the collectionView.

if your collection view is connected on storyboard and the delegate and datasource is set there, and you provide the necessary methods for the datasource and delegate, then adding the register call makes the
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath
return a UICollectionView instead of your own subclass of it. So do either but not both.

set your cell identifier name as in code

Related

How to change the background colour of a UICollectionViewCell based on a given value

I have a view controller which contains a UICollectionView. It has re-use identifier ValveCell specified for the prototype cell. It is using a custom subclass of UICollectionViewCell called ValveViewCell.
I have put a couple of text labels on the prototype cell using the Storyboard and I can get the different values to display in multiple cells no problem. There are currently 4 cells, displaying info from 4 different valves.
All I want to do is change the background colour of the cell depending on whether the valve is turned on or off (a boolean value which I can successfully test on).
I am using this code:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ValveViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
Valve *valve = [valveArray objectAtIndex:indexPath.row];
cell.valveID.text = [valve.valveID stringValue];
cell.valveLabel.text = valve.valveLabel;
cell.valveStatus.text = valve.status;
if ([valve isOn]) {
[cell setBackgroundColor:[UIColor greenColor]];
} else {
[cell setBackgroundColor:[UIColor redColor]];
}
return cell;
}
The problem is that it does change the background colour, but it changes every single cell's background colour instead of just the current cell. Any ideas? Thanks in advance!
Easy Fix! Put this as the first line in your method!
ValveViewCell *cell = [[ValveViewCell alloc] init]
and then change
ValveViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
to
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ValveCell" forIndexPath:indexPath];
You're referencing the same cell for the whole collectionView so initializing each cell will fix your issue.

custom cell for UICollectionView

I need to create an app which has a list of items, each item has an image a title, a subtitle a price and a description and I need 2 items per line (so I can't use a UITableView)
Is it possible to use a UICollectionView with custom cell in order to have the result I want or should I search another solution?
The custom cell layout should be like this:
You totally can !
Just create your custom UICollectionViewCell, then go in the "cellForItemAtIndexPath" method in order to use it.
Hope this help :)
1, create a xib file in the subclass of UIcollectionViewCell
2, register your xib in controller's viewdidload fun
[mCollectionView registerNib:[UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"Cell"];
3,
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
return cell;
}
You can definitely customise your UICollectionView's Cell. But you will have to do following steps as well:
Register your Custom Cell to your collection view :
[self.collectionView registerClass:[YourCustomClass class]
forCellWithReuseIdentifier:#"CustomCell"];
Secondly, inside your method : cellForItemAtIndexPath, you will have to call custom cell like this (as you do in tableView's custom cell too):
YourCustomClass *cell = (YourCustomClass *)[collectionView
dequeueReusableCellWithReuseIdentifier:#"CustomCell" forIndexPath:indexPath];
Here is a tutorial to make custom UICollectionView Cell

UICollectionViewCell does not autosize subviews at first appearance

With XCode 6 and iOS 8 I encountered the problem that UICollectionViewCells does not autolayout / autoresize the subviews at first appearance. Once they have been shown and the cell is reused everything is fine.
I put
[cell layoutIfNeeded];
after the dequeueReusableCellWithReuseIdentifier-Statement and everything was fine again.
I had the same issue. I tried to put [cell layoutIfNeeded];, but when I refresh the tableview, not all the cells are refreshed.
With the code [cell layoutSubviews]; just before returning the cell, all cells are updated every time. Here is the complete piece of code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
...
[cell layoutSubviews];
return cell;
}

AVAudioPlayer in cell, how to not release?

I've a collection view with custom cell class.
In each cell I've a player with a specific sound.
When made an Button and link to my code with an IBOutlet, it's doesn't fire even with the fact I have userInteractionEnabled = YES in all my views.
So I decided to play the sound in the collection view controller.
In my cell the player has a property
#property (strong, nonatomic) AVAudioPlayer *voicePlayer;
Then in the collection I have:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
LHFriendVoiceObject *currentFriendVoice = [[LHFriendVoiceObject alloc] initWithNSDictionnary:[self.friendsArray objectAtIndex:indexPath.row]];
[cell hydrateWithFriendVoiceObject:currentFriendVoice];
[cell.voicePlayer prepareToPlay];
//[self.voicesArray addObject:cell.voicePlayer]; tried to stock them in array but doesn't work
return cell;
}
If I play the sound in this method it's work, but I want the sound to be played when I select the cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
Here the sound doesn't play because voicePlayer is nil.
How I can keep my players ?
This code is the problem:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
That first line is wrong. You are calling dequeue. Big mistake! It makes a completely new cell. Do not make a new cell like that! Obviously that new cell will not have any AVAudioPlayer in it.
You already have a cell; it just got selected. Use the indexPath and cellForItemAtIndexPath: to learn out which cell got selected. That is the one you want to talk to.
PS You really should figure out why the button approach didn't work, but it's no big deal at this point.

How to save state of UICollectionViewCell

Please help me, how can I save state of UICollectionViewCell. For example: I have cells with UIWebView and when I dequeueReusableCellWithReuseIdentifier:forIndexPath: returned wrong cell, not for this indexPath and after it UIWebView content will reloaded for correct indexPath with twitches. Thanks!
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NewsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"NEWS_CELL" forIndexPath:indexPath];
if (!cell.isShowed) { // I just added boolean property
cell.isShowed = YES;
/*** some init actions ***/
}
return cell;
}
If I use this method, cells with cell.isShowed == YES return on wrong indexPath. But if I not use cell.isShowed content of UIWebView will reloaded in every showing cell
Sorry for my english :)
See what Apple's UIWebView Class Reference say:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
But UICollectionView inherits from UIScrollView. So you need to redesign your architecture.