Reputation: 5077
While looping the
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {}
method im setting data to my custom cell (an image and a text). I was wondering what's the best way to achieve this.
I can use 2 different array (image array and text array) and do something like:
cell.image setImage: //get image from imageArray with indexPath.row
cell.text.text = [textArray objectAtIndex:indexPath.row];
or use a multi dimensional array like this:
cell.image setImage: [imageArray objectAtIndex:indexPath.row] objectAtIndex:0;
cell.text.text = [textArray objectAtIndex:indexPath.row] objectAtIndex:1;
// or use of dictionary with keys
What method is quicker or more readable?
Upvotes: 1
Views: 86
Reputation: 11834
Personally I think the following is the cleanest solution:
Let's say we have a news app. The array is filled with items for which we create the model NewsItem. The model header could look like this:
NewsItem.h
@interface FSNewsItem : NSObject <NSCoding>
@property (nonatomic, copy, readonly) NSString *title;
@property (nonatomic, copy, readonly) NSURL *URL;
@property (nonatomic, copy, readonly) NSString *time;
@property (nonatomic, copy, readonly) NSString *points;
@property (nonatomic, copy, readonly) NSString *author;
// initialiser
+ (FSNewsItem *)newsItemWithTitleNode:(HTMLNode *)node
subTextNode:(HTMLNode *)subNode;
@end
Now for the cell we create a NewsItemCell. The code for NewsItemCell might look like the following:
NewsItemCell.h
@interface FSNewsItemCell : UITableViewCell
@property (nonatomic, strong) FSNewsItem *newsItem;
@end
NewsItemCell.m
@interface FSNewsCell ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *detailLabel;
@end
@implementation FSNewsItemCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
self.titleLabel = [[UILabel alloc] init];
[self addSubview:_titleLabel];
self.detailLabel = [[UILabel alloc] init];
[self addSubview:_detailLabel];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
const CGRect bounds = self.bounds;
CGFloat width = bounds.size.width - (FS_FLOAT_PADDING * 2) - 15.0f;
_titleLabel.frame = CGRectMake(FS_FLOAT_PADDING, FS_FLOAT_CELL_PADDING_VERTICAL, width, 20.0f);
CGFloat y = _titleLabel.frame.size.height + (FS_FLOAT_CELL_PADDING_VERTICAL * 2);
_detailLabel.frame = CGRectMake(FS_FLOAT_PADDING, y, width, 15.0f);
}
#pragma mark - Private
- (void)setNewsItem:(FSNewsItem *)newsItem
{
if (_newsItem == newsItem)
{
return;
}
_newsItem = newsItem;
self.titleLabel.text = newsItem.title;
if (_newsItem.points && _newsItem.time)
{
self.detailLabel.text = [NSString stringWithFormat:@"%@ | %@", _newsItem.points, newsItem.time];
}
else
{
self.detailLabel.text = newsItem.time;
}
[self setNeedsLayout];
}
Finally, when we want to display the news item in the cell, our code would look like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
FSNewsItemCell *cell = (FSNewsItemCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[FSNewsItemCell alloc] initWithStyle:UITableViewCellStylePlain reuseIdentifier:CellIdentifier];
}
cell.newsItem = [_items objectAtIndex:indexPath.row];
return cell;
}
This is in my opinion the cleanest solution and the approach I take most of the time. I like to keep my view controllers small. I also like the fact that my view controller doesn't have to know which controls my (custom) table view cell has. The table view cell gets full responsibility on how to draw itself depending on the data supplied.
Upvotes: 2
Reputation: 9030
One idea is to create a custom class:
@interface CellInfo : NSObject
@property (....) UIImage *image;
@property (....) NSString *text;
@end
Then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
CellInfo *info = [self.cellInfoArray objectAtIndex:indexPath.row];
cell.image = info.image;
cell.text = info.text;
...
}
Upvotes: 1
Reputation: 112855
I would add a simple data class and put class instances in the NSArray
. Or use a NSArray
of NSDictionary
objects so the items can be addressed by name, not position.
Example class code (classes are very easy these days):
@interface DisplayItems : NSObject
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) UIImage *image;
@end
@implementation DisplayItems
@end
Upvotes: 1