Reuse custom TableViewCell - ios

I have a viewController that contains a programmatically created tableView.
#property (strong, nonatomic) UITableView *numbersTableView;
//...
self.numbersTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, -100, self.view.frame.size.width-20, 50)];
self.numbersTableView.delegate = self;
self.numbersTableView.dataSource = self;
self.numbersTableView.tag = 1;
self.numbersTableView.layer.cornerRadius = 5;
[self.numbersTableView setBounces:false];
[self.numbersTableView setHidden:true];
[self.numbersTableView registerClass:[AZGCountryCell class] forCellReuseIdentifier:#"NumbersTableViewCell"];
[self.view addSubview:self.numbersTableView];
For the prototype cell I want to use a prototype that I created somewhere else in another viewController and I designed It in storyboard.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (tableView.tag == 1) { //tableView == self.numbersTableView
NSString *cellID = #"NumbersTableViewCell";
AZGCountryCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[AZGCountryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.countryName.text = self.numbersArray[indexPath.row].number;
cell.flagImageView.image = [UIImage imageNamed:self.numbersArray[indexPath.row].country];
return cell;
}
}
And my custom cell contains one UIImageView and one UILabel but when I run the code the cells are empty and I can see the UIImageView and UILabel are nil!
#import <UIKit/UIKit.h>
#interface AZGCountryCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIImageView *flagImageView;
#property (strong, nonatomic) IBOutlet UILabel *countryName;
#property (strong, nonatomic) IBOutlet UILabel *countryCode;
#end
#import "AZGCountryCell.h"
#implementation AZGCountryCell
#synthesize flagImageView;
#synthesize countryName;
- (void)awakeFromNib {
[super awakeFromNib];
self.flagImageView.layer.cornerRadius = self.flagImageView.frame.size.width/2;
self.flagImageView.layer.masksToBounds = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
#end
Then what should I do to have properly filled cells in my numbersTableView?

Unfortunately you can't reuse a table cell you've defined in a table view in a storyboard in your separate class.
In order for you to be able to share your cell between the different views, you'll have to extract the view to a separate nib and register that nib go be used on both tables.
Alternatively you can implement the cell's UI in code in the table view cell subclass.

You getting empty cell because custom tableview cell not registered, use
[self.numbersTableView registerNib:[UINib nibWithNibName:#"AZGCountryCell" bundle:nil] forCellReuseIdentifier:#"NumbersTableViewCell"];
instead of
[self.numbersTableView registerClass:[AZGCountryCell class] forCellReuseIdentifier:#"NumbersTableViewCell"];

Related

How do I get this UITableView to display?

I can't figure out how to get this UITableView to display.
The code creates the table fully programmatically except for the nib.
The nib is a simple cell that works in other UITableViews in the same app.
When the table view is created and added as a subview to the view and reloadData is called then numberOfSectionsInTableView: and tableView:numberOfRowsInSection: are both called. They both return 1. (I checked in the debugger.)
However tableView:cellForRowAtIndexPath: is never called.
I add the tableView to it's parent view with a NSLayoutConstraint that forces it's height, but nothing is displayed in that spot.
The view hierarchy debugger shows nothing in that spot and that there isn't a view on top of the table.
The app runs without any error or crashes.
I would appreciate your help.
#interface MyViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
#end
#implementation MyViewCell
#end
#interface MyDataTableEntry : NSObject
#property (nonatomic, strong) NSString* title;
#end
#implementation MyDataTableEntry
#end
#interface MyDataTable : NSObject <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSArray *rows;
#property (strong, nonatomic) UINib* nib;
#end
#implementation MyDataTable
- (UINib*)getAndRegisterNib:(NSString*)reuseIdentifier {
UINib* nib = [UINib nibWithNibName:reuseIdentifier bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:reuseIdentifier];
return nib;
}
- (id)initWithRows:(NSArray*) rows andView:(UIView*)view {
if (self = [super init]) {
self.rows = rows;
self.tableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
self.nib = [self getAndRegisterNib:#"PrototypeCell"];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.backgroundColor = [UIColor grayColor];
}
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.rows.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PrototypeCell" forIndexPath:indexPath];
MyDataTableEntry* entry = self.rows[indexPath.row];
[cell.button setTitle:entry.name forState:UIControlStateNormal];
cell.button.backgroundColor = [UIColor blueColor];
return cell;
}
#end
Here is a snippet that creates the table:
MyDataTableEntry* entry = [[MyDataTableEntry alloc] init];
entry.title = #"hello";
self.dataTable = [[MyDataTable alloc] initWithRows:#[entry] andView:self.view];
[self.view addSubview:self.dataTable.tableView];
[self.dataTable.tableView setNeedsLayout];
[self.dataTable.tableView layoutIfNeeded];
[self.dataTable.tableView reloadData];
Without confirming in a debugger:
The problem is here:
self.dataTable = [[MyDataTable alloc] initWithRows:#[entry] andView:self.view];
[self.view addSubview:self.dataTable];
self.dataTable is an NSObject. The second line should read something like this:
[self.view addSubview:self.dataTable.tableView];
I would also suggest that you engage in some refactoring. MyDataTable is not a view. It's a controller. So rename to MyDataTableController. Then the bug would have been more obvious.
I would also ask why you are doing this in code? you are already using nibs. So why not go to storyboards. Doing that and using UITableViewController as a base class should enable you to remove a lot of the code and potential bugs.

Populate UITableView from NSMutableArray

Having an issue where the array values do not display in my tableview cells, but can be printed out correctly with NSLog. Thanks in advance for your help!
TableViewCell .h
#import <UIKit/UIKit.h>
#interface TableViewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (strong, nonatomic) IBOutlet UILabel *label;
#end
TableViewController.h
#import <UIKit/UIKit.h>
#interface TableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
#property(nonatomic, strong) NSMutableArray *imagesArray;
#property(nonatomic, strong) NSMutableArray *namesArray;
#end
TableViewController.m
#import "TableViewController.h"
#import "TableViewCell.h"
#interface TableViewController ()
#end
#implementation TableViewController
#synthesize primaryWeaponNames = _primaryWeaponNames;
- (void)viewDidLoad {
[super viewDidLoad];
[self setupArrays];
}
- (void)setupArrays {
_namesArray = [[NSMutableArray alloc] initWithObjects:
#"NAME1", #"NAME2", #"NAME3"
nil];
self.imagesArray = [[NSMutableArray alloc] initWithObjects:
#"IMG1", #"IMG2", #"IMG3"
nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return _namesArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableViewCell";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.nameLabel.text = [NSString stringWithFormat:#"%#", [_namesArray objectAtIndex:indexPath.row]];
NSLog(#"%#", _namesArray[indexPath.row]);
cell.image.image = [self.imagesArray objectAtIndex:indexPath.row];
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
When you make the cell in a xib file, you should register the nib in viewDidLoad. Since you didn't do that, the dequeue method will return nil, and you're just creating a default cell (in the if (cell == nil) clause) instead of your custom cell. The default cell doesn't have a nameLabel or image property, so the lines to set the values of those outlets won't do anything.
[self.tableView registerNib:[UINib nibWithNibName:#"Your nib name here" bundle:nil] forCellReuseIdentifier:#"TableViewCell];
In your TableViewController class, you need to include
self.tableView.delegate = self;
self.tableView.datasource = self;
in your viewDidLoad method. Or you can do this in interface builder by right click dragging the table view in your tableview controller to file's owner and setting delegate, then repeat for datasource

Empty custom prototype cell

I'm new in iPhone development and have problem with prototype cell.
In my storyboard, I have navigation controller. I pushed it with view controller (as main window), it has a button, when I click it I open tableView controller with custom prototype cell
- (IBAction)searchClick:(id)sender {
CNCarTableController *car = [[CNCarTableController alloc]init];
[self.navigationController pushViewController:car animated:TRUE];
}
But when it opens it has empty rows
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: ( NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TransportCell";
CNTransportCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if(cell == nil){
cell = [[CNTransportCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//cell.textLabel.text = #"bmv";
cell.name = (UILabel*) [cell viewWithTag:100];
[cell.name setText:#"a text"];
cell.number.text = #"number";
cell.car.text = #"car";
return cell;
}
But if will use cell.textLabel.text = #"bmv"; all works ok. But for custom cell way with tags or cell.lbl.text don't work. What is wrong there? Can it be a nuance of navigation controller with view controller?
Custom cell code:
#interface CNTransportCell : UITableViewCell
#property (nonatomic,weak) IBOutlet UILabel *name;
#property (nonatomic,weak) IBOutlet UILabel *number;
#property (nonatomic,weak) IBOutlet UILabel *car;
#end
#implementation CNTransportCell
#synthesize name;
#synthesize number;
#synthesize car;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
you have done small mistake there. Your custom cell class is "CNPlayerCell" & you are allocating new cells from "CNTransportCell" class.
One more thing, have you assigned custom class to your prototype cell in IB? (In identity inspector)

Accessing the IBOutlets's properties in the custom UITableViewCell with an IBAction

I'm a newbie in objective-c and iOS
I created several custom table cells with outlets in it. But I'm not sure if I use the right way.
What I want to do is to get the property of an Outlet which is inside the custom cell, by an IBAction defined in the table view controller.
I have a custom table cell called KolonNumberCell, and a UISlider in it.
I want to define an IBAction called playNumbers in the UITableViewController. The slider seems to work fine in the custom cell. I can get its value.
But I cannot figure out how to get the value of this slider when the playButton outlet is tapped.
I would be so grateful if you could give me some information or show me a way.
Thanks in advance
TableController.h
#import <UIKit/UIKit.h>
#class KolonNumberCell;
#class BankoNumberCell;
#interface TableViewController : UITableViewController{
NSArray *bundleArray;
IBOutlet KolonNumberCell *kolonCell;
IBOutlet BankoNumberCell *bankoCell;
UIButton *playButton;
}
#property (strong) IBOutlet KolonNumberCell *kolonCell;
#property (strong) IBOutlet BankoNumberCell *bankoCell;
#property (nonatomic,retain) NSArray *bundleArray;
#property (nonatomic,retain) IBOutlet UIButton *playButton;
- (void)playNumbers:(id)sender;
#end
part of TableController.m
#import "TableViewController.h"
#interface TableViewController ()
#end
#implementation TableViewController
#synthesize bundleArray,kolonCell,bankoCell,playButton;
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *bundle1 = [[[NSBundle mainBundle] loadNibNamed:#"KolonNumberCell" owner:self options:nil] objectAtIndex:0];
NSArray *bundle2 = [[[NSBundle mainBundle] loadNibNamed:#"BankoNumberCell" owner:self options:nil] objectAtIndex:0];
bundleArray = [[NSArray alloc] initWithObjects:bundle1,bundle2, nil];
}
- (void)playNumbers:(id)sender
{
NSLog(#"button");
// Get the value of the slider in KolonNumberCell... but how?
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
tableView.allowsSelection = NO;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [bundleArray objectAtIndex:indexPath.section];
}
return cell;
}
#end
One of my customtableviewcell implementation file
#import "KolonNumberCell.h"
#implementation KolonNumberCell
#synthesize label,slider;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
self.backgroundView = [[UIImageView alloc] initWithImage:[ [UIImage imageNamed:#"doubleRound.png"] stretchableImageWithLeftCapWidth:0.0 topCapHeight:0.0]];
}
- (IBAction)sliderChanged:(id)sender
{
[label setText:[NSString stringWithFormat:#"%i",(int)slider.value]];
}
+ (NSString *)reuseIdentifier {
return #"Cell";
}
#end
Your design is odd because your code will become really messy with more Cells.
Matt Gallagher has a nice implementation for Custom TableViews. He is using the TableViewCell as a Controller and puts all the logic related to cell in the cells class. The discussion thread on Stack Overflow:
CustomTableViewController
If you still want to do it your way:
Give your Slider a tag: slider.tag = x //Make sure that the tag is unique
In PlayNumbers:
UISlider *slider = (UISlider *)[[[bundleArray objectAtIndex:0] contentView] viewWithTag:x];
NSLog(#"%i",(int)slider.value);
Edit: thanks for correcting the syntax

Custom UITableViewCell not showing content

I'm having major issues trying to get a custom UITableViewCell show any custom labels/controls. I have a similar project using same code and it works perfectly...the only difference is I use the table cell in a UITableViewController, as opposed to the problem page where I use the table cell in a UITableView embedded in a UIViewController. . Some searching of stackoverflow has suggested the following issues, all of which I have set up correctly:
1) CellIdentifier in tableView:cellForRowAtIndexPath: matches the storyboard identifier
2) All IBOutlets are connected properly
I suspect it may be something to do with the way I load the page (I do lots of page loading in viewDidLayoutSubviews method as I use storyboard autolayout and so I need access to frame sizes etc which isn't available in viewDidLoad)
Any suggestions?
Andy
EDIT: By the way it works perfectly if I use a standard UITableViewCell and instead of my custom label just use the cell.textLabel.text = #"..." etc. It seems to be something related to my custom cell.
viewController.h
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (weak, nonatomic) IBOutlet UIView *flipContainerView;
...
#end
viewController.m
#implementation ViewController
#synthesize tableView = _tableView;
#synthesize flipContainerView = _flipContainerView;
...
- (void)viewDidLayoutSubviews {
self.tableView.frame = CGRectMake((self.flipContainerView.frame.size.width / 2) - (self.flipContainerView.frame.size.width / 2),
(self.flipContainerView.frame.size.height / 2) - (self.flipContainerView.frame.size.height / 2),
self.flipContainerView.frame.size.width,
self.flipContainerView.frame.size.height);
...
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"List Cell";
ListCell *cell = (ListCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[ListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.testLabel.text = nil;
cell.testLabel.text = #"test value";
return cell;
}
ListCell.h
#interface ListCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *testLabel;
#end
ListCell.m
#import "ListCell.h"
#implementation ListCell
#synthesize testLabel = _testLabel;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end

Resources