[IOS] separating DataSource and building a lighter UIViewController
I saw an article in objccn. io to build a lighter View Controllers, so I can further understand it here.
Xinjiang project, learn -- tableview, class prefix is LT, start our experiment.
First, you need to drag a UITableView In the StoryBoard, declare the tableView variable in the header file, and establish a connection:
Create an ArrayDataSource class as the DataSource of TableView. The purpose is to separate DataSource from the original ViewController:
//// ArrayDataSource.h// objc.io example project (issue #1)//#import
typedef void (^TableViewCellConfigureBlock)(id cell, id item);@interface ArrayDataSource : NSObject
- (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;- (id)itemAtIndexPath:(NSIndexPath *)indexPath;@end
//// ArrayDataSource.h// objc.io example project (issue #1)//#import ArrayDataSource.h@interface ArrayDataSource ()@property (nonatomic, strong) NSArray *items;@property (nonatomic, copy) NSString *cellIdentifier;@property (nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;@end@implementation ArrayDataSource- (id)init{ return nil;}- (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock{ self = [super init]; if (self) { self.items = anItems; self.cellIdentifier = aCellIdentifier; self.configureCellBlock = [aConfigureCellBlock copy]; } return self;}- (id)itemAtIndexPath:(NSIndexPath *)indexPath{ return self.items[(NSUInteger) indexPath.row];}#pragma mark UITableViewDataSource- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.items.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath]; id item = [self itemAtIndexPath:indexPath]; self.configureCellBlock(cell, item); return cell;}@end
We can see that the DataSource management class accepts three variables for initialization:
1. anItems is an object that stores table data. It is an NSArray object that stores encapsulated objects. We don't know what type it is, so we can use id to retrieve the elements in it.
2. cellIdentifier: Cell identifier. It is used to specify the cells used by TableView. It is the unique identifier of a Cell. It can be specified during Cell creation and design.
3. configureCellBlock: A block used to set each cell. because we do not know the specific item format, we do not know how to initialize the data in a cell. We need to use a block to set it, because the purpose of this block is to apply the item data to the cell, the block accepts two parameters, cell and item.
Next, add an LTMyCell class as the custom cell class. Add two labels to xib to display data:
Connect the two labels in xib with the. h header file. The header file after the connection is as follows:
+ (UINib *)nib;@property (weak, nonatomic) IBOutlet UILabel *photoTitleLabel;@property (weak, nonatomic) IBOutlet UILabel *photoDateLabel;
To modify the. m file, follow these steps:
+ (UINib *)nib{ return [UINib nibWithNibName:@PhotoCell bundle:nil];}- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{ [super setHighlighted:highlighted animated:animated]; if (highlighted) { self.photoTitleLabel.shadowColor = [UIColor darkGrayColor]; self.photoTitleLabel.shadowOffset = CGSizeMake(3, 3); } else { self.photoTitleLabel.shadowColor = nil; }}
Next, to create an LTPhoto encapsulation class, we need to package the data used for display:
//// LTPhoto.h// learn-tableview//// Created by why on 8/11/14.// Copyright (c) 2014 why. All rights reserved.//#import
@interface LTPhoto : NSObject
@property (nonatomic, copy) NSString* name;@property (nonatomic, strong) NSDate* creationDate;@end//// LTPhoto.m// learn-tableview//// Created by why on 8/11/14.// Copyright (c) 2014 why. All rights reserved.//#import LTPhoto.hstatic NSString * const IdentifierKey = @identifier;static NSString * const NameKey = @name;static NSString * const CreationDateKey = @creationDate;static NSString * const RatingKey = @rating;@implementation LTPhoto- (void)encodeWithCoder:(NSCoder*)coder{ [coder encodeObject:self.name forKey:NameKey]; [coder encodeObject:self.creationDate forKey:CreationDateKey];}- (BOOL)requiresSecureCoding{ return YES;}- (id)initWithCoder:(NSCoder*)coder{ self = [super init]; if (self) { self.name = [coder decodeObjectOfClass:[NSString class] forKey:NameKey]; self.creationDate = [coder decodeObjectOfClass:[NSDate class] forKey:CreationDateKey]; } return self;}@end
After writing the LTPhoto encapsulation object, we can extend the Category of the original MyCell. Create a new Category:
The Code is as follows:
#import LTMyCell.h@class LTPhoto;@interface LTMyCell (ConfigureForPhoto)- (void)configureForPhoto:(LTPhoto *)photo;@end//// LTMyCell+ConfigureForPhoto.m// learn-tableview//// Created by why on 8/11/14.// Copyright (c) 2014 why. All rights reserved.//#import LTMyCell+ConfigureForPhoto.h#import LTPhoto.h@implementation LTMyCell (ConfigureForPhoto)- (void)configureForPhoto:(LTPhoto *)photo{ self.photoTitleLabel.text = photo.name; self.photoDateLabel.text = [self.dateFormatter stringFromDate:photo.creationDate];}- (NSDateFormatter *)dateFormatter{ static NSDateFormatter *dateFormatter; if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.timeStyle = NSDateFormatterMediumStyle; dateFormatter.dateStyle = NSDateFormatterMediumStyle; } return dateFormatter;}@end
Next, specify the DataSource of TableView in ViewController. The code for modifying the m file is as follows:
//// LTViewController.m// learn-tableview//// Created by why on 8/11/14.// Copyright (c) 2014 why. All rights reserved.//#import LTViewController.h#import ArrayDataSource.h#import LTMyCell.h#import LTMyCell+ConfigureForPhoto.h#import LTPhoto.hstatic NSString * const PhotoCellIdentifier = @LTMyCell;@interface LTViewController ()
@property (nonatomic, strong) ArrayDataSource *photosArrayDataSource;@end@implementation LTViewController- (void)viewDidLoad{ [super viewDidLoad];// Do any additional setup after loading the view, typically from a nib. [self setupTableView];}- (void)setupTableView{ TableViewCellConfigureBlock configureCell = ^(LTMyCell *cell, LTPhoto *photo) { [cell configureForPhoto:photo]; }; NSMutableArray *photos = [[NSMutableArray alloc] init]; for (int i = 0; i < 10; i++) { LTPhoto *photo = [[LTPhoto alloc] init]; photo.name = @Hello; photo.creationDate = [NSDate date]; [photos addObject:photo]; } self.photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos cellIdentifier:PhotoCellIdentifier configureCellBlock:configureCell]; _tableVIew.dataSource = self.photosArrayDataSource; [_tableVIew registerNib:[LTMyCell nib] forCellReuseIdentifier:PhotoCellIdentifier]; }#pragma mark UITableViewDelegate- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@Click!);}- (void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}@end
In this way, the basic DataSource separation is implemented.