I am trying to display some text in UICollection view. But i am getting the error that
Property cell label not fount on object of type
UICOllectionViewCell
.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate>
#end
.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 10;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier =#"cell";
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.cellLabel.text = #"Sample Text";
return cell;
}
#end
I have already set the delgate methods of UICollectionView.
Here is the Screenshot of Error
First note that even if you have a custom cell you are dequeing your collection view cell to a custom one :
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
In compile time the compiler doesn't know you are trying to use your custom cell, therefore that property doesn't exist.
Be sure that you:
Created a custom UICollectionViewCell that has your cellLabel property
That you registered your cell via code OR you used your cell identifier in the Interface Builder
That you imported your cell and you are using it in cellForItemAtIndexPath
Do you have your cellLabel outlet set in interface builder?
If NO then make one.
You should have something like this in your cell's .h file:
#property (weak, nonatomic) IBOutlet UILabel *cellLabel;
then later you really just need to do this:
cell.cellLabel.text = #"";
You can also make a label like this,
UILabel *cellLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, cell.bounds.size.width, 40)]; //custom size
[cell.contentView addSubview:cellLabel];
and use it like
cell.cellLabel.text = #"Sample Text";
There are tutorial on UICollectionView you can have a look on this link.
Related
Hi there i have a slight problem with my UICollectionView. i don't currently have any settings set for spacing yet i seem to have a huge gap between my cells of which is very annoying if would be helpful if someone could tell me how to resolve this? id assume its something very simple.
Below is an example of whats happening to my CollectionViewCells:
Custom cell.h
#import <UIKit/UIKit.h>
#interface CustomCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *IconImage;
#property (weak, nonatomic) IBOutlet UILabel *IconLabel;
#property (weak, nonatomic) IBOutlet UILabel *IconDescription;
#end
groupsviewcontroller.m
#import "GroupsViewController.h"
#import "CustomCell.h"
#interface GroupsViewController ()
{
NSArray *arrayOfImages;
NSArray *arrayOfDescriptions;
}
#end
#implementation GroupsViewController
{
NSString *reuseIdentifier;
}
- (void)viewDidLoad
{
[super viewDidLoad];
reuseIdentifier= #"SmallIcon";
[[self GroupsCollectionView]setDataSource:self];
[[self GroupsCollectionView]setDelegate:self];
arrayOfImages = [[NSArray alloc]initWithObjects:#"sin.png", nil];
arrayOfDescriptions = [[NSArray alloc]initWithObjects:#"Sin", nil];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [arrayOfDescriptions count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
[[cell IconImage]setImage:[UIImage imageNamed:[arrayOfImages objectAtIndex:indexPath.item]]];
[[cell IconLabel]setText:[arrayOfDescriptions objectAtIndex:indexPath.item]];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//Dispose of any resources that can be recreated.
}
- (IBAction)cellToggleAction:(id)sender {
//need to add toggle button to toggle between three different views
//small icon
//list view
//large icon
}
#end
1) You should check your CustomCell class, see if any size constraint is applied. Simply set your cell's background as some color and the actual cell size will be highlighted.
2) Use (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath to help yourself set the proper cell size. This func comes with UICollectionViewDelegateFlowLayout :)
I have a UITableView. Each cell contains horizontal collection view. When I scroll the table, collection view contains too much cells. I guess it is because the cells are not properly reused. In the illustration, the grey cells were not suppose to be there.
What is the proper code that I should put in the reuseCell? I tried the following but it made the app crash
over
ride func prepareForReuse()
{
super.prepareForReuse()
channelsCollectionView = UICollectionView()
}
It should be
//Reset the datasource
channelsCollectionView.dataSourceArray = []()
//Reload data of collectionView
channelsCollectionView.reloadData()
Again its depends, this is one way of doing
Please follow the below steps. That will work perfectly fine CollectionView inside UITableViewCell.
Make subclass of UICollectionView like this.
#interface MyCollectionView : UICollectionView <UICollectionViewDataSource, UICollectionViewDelegate>
/* Properties */
#property (nonatomic, strong) NSMutableArray *imagesArray;
#end
In your MyCollectionView.m file
#interface MyCollectionView ()
#property (nonatomic, strong) UICollectionViewFlowLayout *flowLayout;
#end
#implementation MyCollectionView
-(void)awakeFromNib {
[super awakeFromNib];
self.dataSource = self;
self.delegate = self;
//Set CollectionView Layout
[self setCollectionViewLayout:self.flowLayout];
}
#pragma mark - CollectionView DataSource methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return _imagesArray.count;
}
-(UICollectionViewFlowLayout *)flowLayout{
// set your layout here
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
[_flowLayout setSectionInset:UIEdgeInsetsMake(topSpacing, leftMargin, bottomSpacing, rightMargin)];
[_flowLayout setMinimumInteritemSpacing:cellSpacing];
[_flowLayout setMinimumLineSpacing:lineSpacing];
[_flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[_flowLayout setItemSize:CGSizeMake(cellWidth, cellHeight)];
return _flowLayout;
}
#pragma mark - setter method
-(void)setImagesArray:(NSMutableArray *)imagesArray {
_imagesArray = imagesArray;
[self reloadData];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// configure cell here
}
In your ViewController.m having UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
cell.myCollectionView.imagesArray = //Array here
return cell;
}
You need to set fix height of your collectionView in TableViewCell. As you've horizontal collectionView.
i have created some code in my button to toggle between my cell identifier of which does so pretty well but obviously i needed to set and initial cell identifier of which is small icon, so how would i go about remove that cell identifier and replacing it with another once the button is clicked. My current code is as follows:
GroupsViewController.m
#import "GroupsViewController.h"
#import "CustomCell.h"
#interface GroupsViewController ()
{
NSArray *arrayOfImages;
NSArray *arrayOfDescriptions;
}
#end
#implementation GroupsViewController
{
NSString *reuseIdentifier;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[self GroupsCollectionView]setDataSource:self];
[[self GroupsCollectionView]setDelegate:self];
reuseIdentifier= #"SmallIcon";
arrayOfImages = [[NSArray alloc]initWithObjects:#"?.png", nil];
arrayOfDescriptions = [[NSArray alloc]initWithObjects:#"?", nil];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [arrayOfDescriptions count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
[[cell IconImage]setImage:[UIImage imageNamed:[arrayOfImages objectAtIndex:indexPath.item]]];
[[cell IconLabel]setText:[arrayOfDescriptions objectAtIndex:indexPath.item]];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//Dispose of any resources that can be recreated.
}
- (IBAction)cellToggleAction:(id)sender {
if([reuseIdentifier isEqualToString:#"SmallIcon"])
reuseIdentifier=#"ListView";
else if
([reuseIdentifier isEqualToString:#"ListView"])
reuseIdentifier=#"LargeIcon";
else if
([reuseIdentifier isEqualToString:#"LargeIcon"])
reuseIdentifier=#"SmallIcon";
[self.GroupsCollectionView reloadData];
}
#end
CustomCell.h
#import <UIKit/UIKit.h>
#interface CustomCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *IconImage;
#property (weak, nonatomic) IBOutlet UILabel *IconLabel;
#end
I assume its to do with me setting the reuseIdentifier in the
- (void)viewDidLoad so that i didn't get any errors so that i hadn't set one, so really what i am asking for is a way to set the initial reuseidzntifier and replace it will the following when i toggle between the button clicks.
Also it would be helpful if someone could point me in the right direction as to adding icon images to each click of the button.
The problem happens when i am clicking the button as shown in the following images, the cells themselves change but the initial cell identifier stays put.
From what I understand your UICollectionViewCells are working fine. You just need to adjust their size when cells are toggled.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize cellSize;
// Return required size based on your identifiers
if([reuseIdentifier isEqualToString:#"SmallIcon"])
cellSize = CGSizeMake(50, 50); // Sample size
else if
([reuseIdentifier isEqualToString:#"ListView"])
cellSize = CGSizeMake(80, 80); // Sample size
else if
([reuseIdentifier isEqualToString:#"LargeIcon"])
cellSize = CGSizeMake(120, 120); // Sample size
return cellSize;
}
I have implemented my own UITableViewCell and created a .xib for it. I have connected all the labels using a strong IBOutlet and initialized the UILabels in the awakeFromNib() method. However, whenever I run the iOS Simulator, I run into an issue where the UILabel is (null) in NSLog.
I am wondering if it has to do with how I am loading in the text for the UILabel. I have tried to create a shortened version of the project below that outlines the issue I'm running into.
I would also like to note that I can click on the actual rows, but that there is still no text displaying.
My code:
ToDoCell.h
#import <UIKit/UIKit.h>
#interface ToDoCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *minutesLeft;
#property (strong, nonatomic) IBOutlet UILabel *hoursLeft;
#property (strong, nonatomic) IBOutlet UILabel *daysLeft;
#property (strong, nonatomic) IBOutlet UILabel *taskLabel;
#end
ToDoCell.m
#import "ToDoCell.h"
#implementation ToDoCell
#end
ToDoViewController.m
#import "ToDoViewController.h"
#import "ToDoCell.h"
#interface ToDoViewController ()
#property NSMutableArray *toDoItems;
#end
#implementation ToDoViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
}
- (void)loadInitialData {
NSString *item1 = #"Testing";
[self.toDoItems addObject:item1];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ToDoCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ToDoCell" forIndexPath:indexPath];
cell.taskLabel.text = #"Testing";
NSLog(#"Fudge Monkeys: %#", cell.taskLabel.text);
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
#end
Issue is you are creating new objects for labels but then you are not adding them to superview but calling [self addSubview:label] ssigning them to properties does not add them to super view.
But this is totally unnecessary you should not init them in awakeNib. , and one thing more I will say about your code now you don't need to use #synthesis anymore as well. Any particular reason you are making IBOutlets strong?
Update you need to register nib with tableView first add following lines in viewDidLoad
[tableView registerNib:[UINib nibWithNibName:#"ToDoCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"ToDoCell"];
You can read more about this here
If the UILabel instances are connected in Interface Builder via IBOutlet, you must not initialize them explicitly.
Just delete the complete awakeFromNib() method
Add this in viewDidLoad
NSString *strName = NSStringFromClass([ToDoCell class]);
[self.toDoItems registerNib:[UINib nibWithNibName:strName bundle:nil] forCellReuseIdentifier:strName];
You are using xib file but not loading it by registering it for the tableView. This is required when you use separate xib file. If you do not register, then only class will load and xib won't. And your awakeFromNib won't be called.
First of all delete awakeFromNib and make sure that you gave Cell Identifier in cell nib file.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ToDoCell";
ToDoCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (!cell)
cell = [[ToDoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: cellIdentifier];
cell.taskLabel.text = #"Testing";
return cell;
}
Don't forget to add following code for register nib.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.tableView registerNib:[UINib nibWithNibName:#"ToDoCellTableViewCell" bundle:nil] forCellReuseIdentifier:#"ToDoCell"];
}
Here is the sample code for your problem.
May this help to solve your problem.
You .xib why cell should be set through:
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
ToDoCell *cell = [tableView dequeueReusableCellWithIdentifier:[ToDoCell reuseIdentifier]];
if (!cell) {
cell = (ToDoCell *)
[[NSBundle mainBundle] loadNibNamed:#"ToDoCell" owner:self options:nil].firstObject;
}
cell.taskLabel.text = #"Testing";
NSLog(#"Fudge Monkeys: %#", cell.taskLabel.text);
return cell;
}
My app has a home screen where I show user posts loaded from the server. My problem is that I use UIView for each post, but it takes up a lot of space (also the user keeps on scrolling making it more memory consuming). Ex:
UIView* box=[[UIView alloc]initWithFrame:CGRectMake(0, postY, maxWidth, 500)];
[box setTag:(NSInteger)[post_id[i] integerValue]];
[box setBackgroundColor:[UIColor whiteColor]];
//Profile pic+++
UIImageView* profile_img=[[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
profile_img.layer.cornerRadius=profile_img.frame.size.width/2; //Make it round
profile_img.layer.masksToBounds=YES; //Make it round
profile_img.layer.borderWidth=0.5;
profile_img.layer.borderColor=[rgb(214, 222, 231) CGColor];
[box addSubview:profile_img];
And so on...
Does anyone know a better way of doing this? I tough of UITableCellView but it seems to be odd doing this task this way
I recommend you use a UITableViewController and then subclass UITableViewCell to create a custom cell for you to display the data. A UITableViewController instance contains a UITableView and you display the data by setting it in your custom UITableViewCell subclass. So basically, a UITableView contains various UITableViewCell and use the delegate methods to respond to events and actions on your table.
// YourCustomTableViewCell.h
#import <UIKit/UIKit.h>
#interface YourCustomTableViewCell : UITableViewCell
// Setup the properties for the cell, e.g
#property (strong, nonatomic) IBOutlet UIImageView *profileImageView; // Connect to outlet in storyboard file
#end
// YourCustomTableViewCell.m
#import "YourCustomTableViewCell.h"
#implementation YourCustomTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.profileImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
}
return self;
}
- (void)awakeFromNib
{
// Use this method to setup frames and sizes of your properties
self.profileImageView.layer.cornerRadius = profileImageView.frame.size.width/2; //Make it round
self.profileImageView.layer.masksToBounds = YES; //Make it round
self.profileImageView.layer.borderWidth=0.5;
self.profileImageView.layer.borderColor = [rgb(214, 222, 231) CGColor];
}
#end
// YourTableViewController.h
#import <UIKit/UIKit.h>
#interface YourTableViewController : UITableViewController
#end
// YourTableViewController.m
#import "YourTableViewController.h"
#import "YourCustomTableViewCell.h"
#interface YourTableViewController ()
#end
#implementation YourTableViewController
- (void)viewDidLoad
{
// Setup your data source for the table
self.tableView.dataSource = self;
// Setup other stuff after loading the view
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; // Return the number of sections you want in the table view
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows for each section, in your case this would be something like this
return self.posts.count; // If your data is stored in an array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"YourCustomCell";
YourCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (!cell){
cell = [[YourCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
// Configure the cell...
// Here you add the code to display the data in the cell e.g.
[cell.profileImageView setImage:yourImageToDisplay];
return cell;
}
#end
As the comment said, you'd better choose UITableView as the posts' container and inherit from UITableViewCell as your box view.
Detailedly speaking much more, suppose the class inherited from UITableViewCell named MyTableViewCell, and you treat its contentView as your UIView *box. After that, you could tell the UITableView to use your MyTableViewCell as the Cell by sending him registerClass:forCellReuseIdentifier:.
Then, you can get MyTableViewCell instance by sending UITableView the
dequeueReusableCellWithIdentifier:forIndexPath: message. After being bound data (telling him display what posts), this instance can be returned to UITableView, which will arrange everything for you. Besides, these usually should be done in the UITableView's dataSource method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.