I'm testing UITableView with a custom TableViewCell. The custom cell is designed in a .xib file and has its own class called cell, which is a subclass of UITableViewCell:
Cell.m
#import "Cell.h"
#implementation Cell
- (void)awakeFromNib
{
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
return self;
}
#end
The ViewController class has the UITableView called table in it. It is also Delegate and Datasource for it. Both is set in the Storyboard. Its code looks like this:
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.table registerClass:[Cell class] forCellReuseIdentifier:#"cell" ];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [self.table dequeueReusableCellWithIdentifier:#"cell"];
return cell;
}
#end
If I run the app, I can see the table and it has the right number of cells. But the custom cell is not shown. Each cell of the table is just white.
I read a couple of post on issues like this but no one helped me. Different Tutorials say it should work like this but it doesn't. I think there may is a stupid mistake in it. Thanks for your help.
You said you're using xib files to instantiate your cells, but you're registering a class instead of xib with this line
[self.table registerClass:[Cell class] forCellReuseIdentifier:#"cell" ];
try using registerNib:forCellReuseIdentifier: instead
I'm guessing You forget to set your custom class name in the *.xib file.
Set Custom Class property to "cell" in *.xib properties. Please check that property.
Related
We use UITableViewCell like this.
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib: [UINib nibWithNibName: Cell bundle: nil] forCellReuseIdentifier: kIdentifier];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *cell = [tableView dequeueReusableCellWithIdentifier: kIdentifier forIndexPath: indexPath];
return cell;
}
When cells are born with some properties(tag), how to get cell's - init method, customize it, and tag the cell?
As I did not see any chance while calling the relative methods.
So how to hook a UITableViewCell/UICollectionViewCell's init method?
Here is a situation:
There are two pages. The cell has a page tag.
Sure, I can add property. Just go a litter farther.
I would recommend creating a simple subclass of UITableViewCell. This way you can create customized table cells with whatever you would like the cell to contain "during" the initialization of the cell. Then you could set your nib file class to, for this example, CustomTableViewCell.
Then, like you already have shown, you can just create your customized cells from your reuseIdentifier:
Additionally, you can intercept the other built in methods awakeFromNib and even prepareForReuse for further customization.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: kIdentifier forIndexPath: indexPath];
// Do anything else here you would like.
// [cell someCustomMethod];
return cell;
}
.h
#import <UIKit/UIKit.h>
#interface CustomTableViewCell : UITableViewCell
- (void)someCustomMethod;
...
#property (nonatomic, nullable) <Some class you want> *somePropertyName;
...
#end
.m
#import "CustomTableViewCell.h"
#implementation CustomTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// Do whatever you would like to do here :)
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code. Do whatever you like here as well :)
}
- (void)prepareForReuse {
[super prepareForReuse];
// And here.. :)
}
#end
init isn't really helpful, since cells are created only rarely and then reused.
That said, when cells are initially created, you can intercept that by overloading awakeFromNib. When they're reused later, prepareForReuse is called.
Don't forget to call the super implementations in both methods.
So I have a custom UITableViewCell:
TestTableViewCell.h
#import <UIKit/UIKit.h>
#interface TestTableViewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *testCellLabel;
#end
TestTabelViewCell.m
#import "TestTableViewCell.h"
#implementation TestTableViewCell
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_testCellLabel = [[UILabel alloc] init];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
And then I have view controller with a table view that uses the custom table view cell. However this issue is that I don't want to use dequeueReusableCellWithIdentifier within the cellForRowAtIndexPath. I instead want to have an array of cells.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
ViewController.m
#import "ViewController.h"
#import "TestTableViewCell.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSArray *myTableViewCells;
#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.
}
- (NSArray *)myTableViewCells {
TestTableViewCell *cell1 = [[TestTableViewCell alloc] init];
cell1.testCellLabel.text = #"one";
cell1.backgroundColor = [UIColor blueColor];
TestTableViewCell *cell2 = [[TestTableViewCell alloc] init];
cell2.testCellLabel.text = #"two";
cell1.backgroundColor = [UIColor greenColor];
if (!_myTableViewCells) {
_myTableViewCells = #[cell1, cell2];
}
return _myTableViewCells;
}
#pragma mark - UITableView delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.myTableViewCells.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestTableViewCell *cell = self.myTableViewCells[indexPath.row];
return cell;
}
#end
The problem is that there is no testCellLabel appearing in the table view cell. I know the cells are there, because I set their background colour.
After talking to a few people, apparently I need to do some sort of loading from the XIB or the NIB for the UI to load properly? Even though the label is defined in the cell in the storyboard.
I know this is going against the norm and that Apple really wants you to use dequeueReusableCellWithIdentifier, but I know it won't work in the situation I need it in. I have done the reading on that much so please don't just tell me to use it. This code example is just very basic for example sake and ease of use.
Any help would be greatly appreciated.
TestTableViewCell *cell1 = [[TestTableViewCell alloc] init];
Creates a new TestTableViewCell object and does not instantiate it from the storyboard like you're thinking it does. Therefor all outlets created will be nil and simply not show up. The fact that you can set the background colour is not evidence that your implementation works.
You need to use dequeueReusableCellWithIdentifier. You say that it doesn't work for your problem.. show me how it doesn't work and I will tell you why you're wrong.
Edit
I see in your comments you say your cell needs a custom setter. Well, when you use dequeueReusableCellWithIdentifier you can do all setup work in awakeFromNib (If using a xib file) OR initWithCoder if you are using the storyboard.
You can create cell without dequeueResableCellWithIdentifer.
[[UITableViewCell alloc]initWithStyle:<#UITableCellStyle#> resueIdentifier:<#(nullable *NSString)#>]
I want to use a UICollectionViewController in my app, for displaying photos.
I derive a class from UICollectionViewController as:
#import <UIKit/UIKit.h>
#interface AlbumCollectionViewController : UICollectionViewController <UICollectionViewDataSource, UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView * cview;
#end
And the implementation is:
#import "AlbumCollectionViewController.h"
#interface AlbumCollectionViewController ()
//#property (weak, nonatomic) IBOutlet UICollectionView * cview;
#end
#implementation AlbumCollectionViewController
static NSString * const reuseIdentifier = #"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
#warning Incomplete method implementation -- Return the number of sections
//return 0;
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
#warning Incomplete method implementation -- Return the number of items in the section
NSUInteger i = 1;
return i;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
return cell;
}
#pragma mark <UICollectionViewDelegate>
/*
// Uncomment this method to specify if the specified item should be highlighted during tracking
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
*/
/*
// Uncomment this method to specify if the specified item should be selected
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
*/
/*
// Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
return NO;
}
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
}
*/
#end
When loading this view controller, I get
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason:
'-[UICollectionViewController loadView] loaded the
"Lyo-Nd-2MQ-view-KhW-kE-Ben" nib but didn't get a UICollectionView.'
On the main storyboard file, I have a UICollectionViewController whose class and storyboard ID are set to 'AlbumCollectionViewController'.
If I need to set up delegate and datasource connections, how can I do this in code? Or can it only be done on the storyboard file.
Also, if that would not seem to be what is causing this, what else can I do to fix this?
Thanks!
Chris
You don't need an IBoutlet cView in your CollectionViewController class. There is already property called .collectionview implemented by the framework.
Get rid of that, and make sure that your collection view is properly linked to its view controller in the storyboard.
Take a look at your storyboard. Then check Settings. I believe you forgot to set the the cell id.
Make sure that you assign delegates and datasource to the collection view, and you also need to assign flow layout to collection view. And you can access the collection view like self.collectionView, you don't need an outlet for collection view as the class itself is subclass of UICollectionViewController
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[self.collectionView setCollectionViewLayout:flowLayout];
If it still didn't work,
Try removing the outlets for collection view in .xib file and again give it to files owner, also do the same with data source and delegate, and make sure that class of file owner is same as collection view controller class
Hope this helps
It reads as if you are mixing up Storyboards and Nibs and using initWithNibName: when you should be using instantiateViewControllerWithIdentifier:
The error you are getting is from loading a nib file. Yet you say you have created the view in a Storyboard. If you were using storyboards and the app wasn't able to find the CollectionView the error would read
NSInvalidArgumentException', reason: 'Storyboard () doesn't contain a view controller with identifier
'AlbumCollectionViewController'
To fix it if you are using a .storyboard file with a UICollectionViewController of type AlbumCollectionViewController inside it, instantiate with
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"NameOfYourStoryboard" bundle:nil];
AlbumCollectionViewController* collectionVC = [sb instantiateViewControllerWithIdentifier:#"AlbumCollectionViewController"];
If you are in fact using .nib file to hold your UICollectionViewController, instantiate with
AlbumCollectionViewController* collectionVC = [[AlbumCollectionViewController alloc] initWithNibName:#"NameOfYourNib" bundle:nil];
I have an image property on my table view cell. I want to populate this image to an image.
My cell looks like:
//.h
#interface GAFriendStatusTableViewCell : PFTableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *friendImage;
#end
//.m
#import "GAFriendStatusTableViewCell.h"
#implementation GAFriendStatusTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.friendImage.image = [UIImage imageNamed:#"user.png"];
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
#end
This doesn't set the image. How can I set the image for this cell within the cell class?
Since your image view is an IBOutlet, I'm assuming you've got your cell layout defined in a .xib or storyboard. That being the case, your initialization code should go in the awakeFromNib method. This is the method that is called when the cell is created from the nib. That's why the //Initialization code comment is there. initWithStyle:reuseIdentifier: is never called in this scenario, which is why your image is not appearing.
Set it in - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Otherwise if you have a Nib or Storyboard you're using then set the default in the prototype cell you are using.
I try to package the UITableView as my own.
The code is:
#interface OPTableView : UIView<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *_dataSource;
id<OPTableviewDelegate>_delegate;
}
#property(retain,nonatomic)id<OPTableviewDelegate>delegate;
#property(retain,nonatomic)NSMutableArray *dataSource;
.m:
#implementation OPTableView
#synthesize delegate=_delegate;
#synthesize dataSource=_dataSource;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
tableView=[[UITableView alloc] initWithFrame:frame];
tableView.delegate=self;
tableView.dataSource=self;
_dataSource=[NSMutableArray array];
[self addSubview:tableView];
[tableView release];
}
return self;
}
#pragma table delegate
- (void)tableView:(UITableView *)tab didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
When I create OPTableView,it can show in the screen.But the problem is that when I did select one table,it would not call the delegate method :didSelectRowAtIndexPath,but what is worse,it breaks down.
Try to set your cell's selection style to some non-none value. Also note you should implement all the required delegate messages of your table - did you do that?
What is OPTableViewDelegate? Your table's delegate is of type OPTableViewDelegate, not UITableViewDelegate.
all,I have made a really stupid mistake.
In the 'initWithFrame' method,the code:_dataSource=[NSMutableArray array]; is absolutely wrong.
I delete this code"_dataSource=[NSMutableArray array]; ",everything works.
Thanks all.