UITableView 做爲Ios開發中最基礎的控件之一,在IOS APP中運用十分普遍。然而不少時候,因爲實際業務的複雜性,在viewController中若是沒有很好地控制UITableView的代碼,則會致使UIViewController的代碼冗餘度太高。json
在MainViewController中,咱們創建了一個TableView ,並設置了DataSource和delegate爲Self,TableView總共呈現了三行數據,每一行會跳轉一個新的ViewController。ruby
#import "MainViewController.h"
#import "StudentViewController.h"
#import "TeacherAndMasterViewController.h"
#import "CustomTableViewCell.h"
static NSString * CellIdr = @"mainCell";
@implementation MainViewController{
NSArray * _stuInfo;
NSArray * _teaInfo;
NSArray * _masterInfo;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self initViews];
[self loadData];
}
- (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 - Init
- (void)initViews
{
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdr];
self.title = @"Main";
}
#pragma mark - Private Logical Methods
- (void)loadData
{
//實際開發中頗有多是服務端返回的json數據。
_stuInfo = @[@{kName: @"Naruto", kGrade: @"三年一班", kScore: @(97)}, @{kName: @"Garra", kGrade: @"三年二班", kScore: @(88)}, @{kName: @"Saski", kGrade: @"二年一班", kScore: @(66)}, @{kName: @"sakura", kGrade: @"三年一班", kScore: @(100)}];
_teaInfo = @[@{kName: @"Kakashi", kGrade: @"三年一班", kLevel: @"上忍"}, @{kName: @"JIRAIYA", kGrade: @"三年二班", kLevel: @"影級"}, @{kName: @"Itachi", kGrade: @"二年一班", kLevel: @"影級"}, @{kName: @"Tsunade", kGrade: @"三年一班", kLevel: @"影級"}];
_masterInfo = @[@{@"name": @"Hagoromo"}];
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdr];
NSInteger row = indexPath.row;
if (row == 0) {
cell.textLabel.text = @"學生信息";
}
else if(row == 1)
{
cell.textLabel.text = @"教師信息";
}
else
{
cell.textLabel.text = @"校長信息";
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSInteger row = indexPath.row;
if (row == 0) {
StudentViewController * stuVc = [[StudentViewController alloc] init];
stuVc.stuInfo = _stuInfo;
[self.navigationController pushViewController:stuVc animated:YES];
}
else
{
...
}
}
@end
MainViewController 模擬器
markdown
咱們準備以學生,老師,校長這種有共性也有差別的對象來舉例,在實際開發中,大部分對象的屬性都有必定的關聯性。
首先說學生對象,咱們設置了名稱,年級,和成績屬性;老師對象與學生對象的區別則是少了成績屬性,多了職稱屬性;校長則只有名稱一個屬性。app
咱們建立一個自定義的TableCell來展現學生信息。ui
#import <UIKit/UIKit.h>
extern NSString * const kName;
extern NSString * const kGrade;
extern NSString * const kScore;
extern NSString * const kLevel;
@interface CustomTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *lblFirst;
@property (weak, nonatomic) IBOutlet UILabel *lblSecond;
@property (weak, nonatomic) IBOutlet UILabel *lblThird;
@property (weak, nonatomic) IBOutlet UIImageView *avatar;
#import "CustomTableViewCell.h"
NSString * const kName = @"name";
NSString * const kGrade = @"grade";
NSString * const kScore = @"score";
NSString * const kLevel = @"level";
@implementation CustomTableViewCell
- (void)awakeFromNib {
// Initialization code
self.avatar.layer.cornerRadius = self.avatar.layer.frame.size.height/2;
self.avatar.layer.masksToBounds = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
這裏咱們的學生屬性有三個,咱們能夠在StudentViewController中給TableView的DataSource一一賦值。atom
#import "StudentViewController.h"
#import "CustomTableViewCell.h"
static NSString * stuCellIdr = @"stuCell";
@implementation StudentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self initViews];
}
- (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 - Init
- (void)initViews
{
[_tableView registerNib:[UINib nibWithNibName:@"CustomTableViewCell" bundle:nil] forCellReuseIdentifier:stuCellIdr];
self.title = @"Stu";
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _stuInfo.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:stuCellIdr];
NSInteger row = indexPath.row;
NSDictionary * stuInfo = _stuInfo[row];
cell.avatar.image = [UIImage imageNamed:@"stu"];
cell.lblFirst.text = stuInfo[kName];
cell.lblSecond.text = stuInfo[kGrade];
cell.lblThird.text = [NSString stringWithFormat:@"%@ 分", stuInfo[kScore]];
cell.lblThird.textColor = [UIColor greenColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 91.f;
}
學生頁面
spa
代碼這麼寫雖然達到了咱們要的效果,可是實際使用中可能會有一些其餘問題。第一個是若是咱們要展現的對象屬性比較多,再加上其餘的一些業務邏輯,頗有可能就致使UIViewController的代碼很長。另外一個是若是還有其餘的ViewController使用到了這個TableCell,則可能要寫另外一份相同或者類似的代碼了,這就加大了咱們代碼的冗餘度。咱們徹底能夠在Cell裏寫一個方法。code
- (void)setStuContent:(NSDictionary *)stuInfo
{
self.avatar.image = [UIImage imageNamed:@"stu"];
self.lblFirst.text = stuInfo[kName];
self.lblSecond.text = stuInfo[kGrade];
self.lblThird.text = [NSString stringWithFormat:@"%@ 分", stuInfo[kScore]];
self.lblThird.textColor = [UIColor greenColor];
}
而後再改掉StudentViewController中DataSource中的代碼。orm
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:stuCellIdr];
NSInteger row = indexPath.row;
NSDictionary * stuInfo = _stuInfo[row];
[cell setStuContent:stuInfo];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
這樣 既減小了UIViewController中的代碼,又增長了自定義Cell的複用性。對象
OK,咱們再來跳轉展現教師信息。
教師頁面:
這個時候咱們會發現教師內容和學生內容有很大的類似性,只有最下面的分數Label變成了職稱Label。相比再去爲Teacher定義一個cell,咱們能夠更好地利用已有的CustomTableCell。
這裏咱們新建一個CustomTableCell的Category,在CustomTableCell的(TeacherConfigure)分類中,咱們添加一個專門爲Teacher設置data的方法。
#import "CustomTableViewCell.h"
@interface CustomTableViewCell (TeacherConfigure)
- (void)setTeaInfo:(NSDictionary *)teaInfo;
@end
#import "CustomTableViewCell+TeacherConfigure.h"
@implementation CustomTableViewCell (TeacherConfigure)
- (void)setTeaInfo:(NSDictionary *)teaInfo
{
self.avatar.image = [UIImage imageNamed:@"tea"];
self.lblFirst.text = teaInfo[kName];
self.lblSecond.text = teaInfo[kGrade];
self.lblThird.text = teaInfo[kLevel];
self.lblThird.textColor = [UIColor orangeColor];
}
@end
這樣咱們教師Controller的代碼就會是這樣:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:teacherCellIdr];
NSInteger row = indexPath.row;
NSDictionary * teaInfo = _TeaMasterInfos[row];
[cell setTeaInfo:teaInfo];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
咱們的MainViewControll裏是將學生,教師,校長分開了;可是在咱們實際開發中頗有可能須要一個UIViewController既能展現教師,又能展現校長。這個時候校長要展現的信息頗有可能又和教師有很大的差異,咱們不得不新建另外一個Cell來展現校長。
咱們固然能夠在同一個ViewController中判斷當前要展現的對象類型,而後在dataSource裏判斷,甚至咱們調用didselect的時候也要進行判斷,例如這樣:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _TeaMasterInfos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = indexPath.row;
if(_dataType == DataTeacher)
{
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:teacherCellIdr];
...
}
else
{
MasterTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:_masterCellIdr];
...
}
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(_dataType == DataTeacher)
{
return 91.f;
}
else
{
return 100.f;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSInteger row = indexPath.row;
if(_dataType == DataTeacher)
{
...
}
else
{
...
}
}
@end
校長頁面:
顯然這樣極可能會 使咱們的UIViewController的代碼達到一個很是長的狀態,在咱們維護代碼的時候將會被這些繁瑣的業務邏輯折磨。
一種比較好的解決方法是把TableView的DataSource和Delegate分割出去。例如咱們能夠創建一個MasterDataSource的對面來管理校長的Cell;
#import <UIKit/UIKit.h>
@interface MasterDataSource : NSObject<UITableViewDataSource, UITableViewDelegate>
- (id)initWithMasterInfo:(NSArray *)masterInfo cellIdr:(NSString *)cellIdr;
@end
#import "MasterDataSource.h"
#import "MasterTableViewCell.h"
@implementation MasterDataSource{
NSArray * _masterInfo;
NSString * _masterCellIdr;
}
- (id)initWithMasterInfo:(NSArray *)masterInfo cellIdr:(NSString *)cellIdr
{
if (self = [super init]) {
_masterInfo = masterInfo;
_masterCellIdr = cellIdr;
}
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _masterInfo.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MasterTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:_masterCellIdr];
NSInteger row = indexPath.row;
NSDictionary * masterInfo = _masterInfo[row];
[cell setMasterContent:masterInfo];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 117.f;
}
這個時候當這個Controller要展現校長信息的時候能夠:
if (_dataType == DataMaster) {
[_tableView registerNib:[UINib nibWithNibName:@"MasterTableViewCell" bundle:nil] forCellReuseIdentifier:masterCellIdr];
self.title = @"Master";
_masterDs = [[MasterDataSource alloc] initWithMasterInfo:_TeaMasterInfos cellIdr:masterCellIdr];
_tableView.delegate = _masterDs;
_tableView.dataSource = _masterDs;
}
這樣咱們的校長信息有關的代碼就分離出去了,避免了Controller中過多的邏輯判斷,大幅減小了UIViewController的代碼。