文明转载评论是对自己尊重也是对学者的鼓励
iOS-通过继承UIScrollView来自定义UITableView实现对代理的详解
一.自定义UITableView (CustomerTableView继承于UIScrollView)
实现一个类继承至UIScrollView,通过代理的语法模式实现UITableView的获得UITableviewCell和UITableviewCell的布局的原理,从而加深对UITableview的原理及对代理模式的理解。
CustomerTableView.h头文件
#import <UIKit/UIKit.h>
@class CustomerTableView;
@protocol CustomerTableViewDelegate <NSObject>
//返回cell的个数
-(NSInteger)numberCellForCustomerTableView:(CustomerTableView *)customerView;
//返回cell的高度
-(CGFloat)cellHeightForCustomerTableView:(CustomerTableView *)customerView ;
//相当于cell
-(UIView *)customerTableView:(CustomerTableView *)customerView cellForIndex:(NSInteger)index;
//返回标题
-(NSString *)customerTableView:(CustomerTableView *)customerView titleForIndex:(NSInteger)index;
@end
@interface CustomerTableView : UIScrollView
//代理
@property (nonatomic,assign)id<CustomerTableViewDelegate> customerDelegate;
//设置代理和frame
-(id)initWithDelegate:(id<CustomerTableViewDelegate>)aDelegate andFrame:(CGRect)aFrame;
@end
CustomerTableView.m文件
#import "CustomerTableView.h"
@implementation CustomerTableView
-(id)initWithDelegate:(id<CustomerTableViewDelegate>)aDelegate andFrame:(CGRect)aFrame{
if (self = [super initWithFrame:aFrame]) {
self.frame = aFrame;
//通过代理得到多少个cell
int numberCell = (int)[aDelegate numberCellForCustomerTableView:self];
//通过代理得到cell的高度,用来设置cell的布局
CGFloat cellHeight = [aDelegate cellHeightForCustomerTableView:self];
CGFloat width = CGRectGetWidth(aFrame);
CGFloat height = CGRectGetHeight(aFrame);
//根据cell的个数来设置contentSize
self.contentSize = CGSizeMake(width, numberCell*cellHeight);
//循环的通过代理来拿到cell title 并根据索引i来设置它们的位置,其他的属性又属性设置
for (int i=0; i<numberCell; i++) {
UIView *cell = [aDelegate customerTableView:self cellForIndex:i];
cell.frame = CGRectMake(0, cellHeight*i, width, cellHeight);
[self addSubview:cell];
NSString *title = [aDelegate customerTableView:self titleForIndex:i];
UILabel *lable = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, width, cellHeight)];
lable.backgroundColor = [UIColor brownColor];
lable.text = title;
[cell addSubview:lable];
}
}
return self;
}
@end
使用:
#import "ViewController.h"
#import "CustomerTableView.h"
@interface ViewController ()<CustomerTableViewDelegate>
@end
@implementation ViewController{
}
- (void)viewDidLoad {
[super viewDidLoad];
CustomerTableView *customer = [[CustomerTableView alloc]initWithDelegate:self andFrame:CGRectMake(0, 0, 320, 400)];
customer.showsHorizontalScrollIndicator = NO;
customer.backgroundColor = [UIColor purpleColor];
[self.view addSubview:customer];
}
//返回cell的高度
-(CGFloat)cellHeightForCustomerTableView:(CustomerTableView *)customerView{
return 100;
}
//返回对应索引的的名字
-(NSString *)customerTableView:(CustomerTableView *)customerView titleForIndex:(NSInteger)index{
return [NSString stringWithFormat:@"item %ld",index];
}
//相当于UITableView的返回cell
-(UIView *)customerTableView:(CustomerTableView *)customerView cellForIndex:(NSInteger)index{
UIView *v = [[UIView alloc]init];
v.backgroundColor = [UIColor redColor];
return v;
}
//返回cell的个数
-(NSInteger)numberCellForCustomerTableView:(CustomerTableView *)customerView{
return 10;
}
@end
运行效果:
二.UITableView的使用
UITableView *table = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 400)];
table.delegate = self;
table.dataSource = self;
[self.view addSubview:table];
代理使用:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
//相当于CustomerTableview返回多少个cell
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
//相当于CustomerTableView 的UIView的高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 100;
}
//相当于CustomerTableview 的UIView
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.textLabel.text = [NSString stringWithFormat:@"item%ld",indexPath.row];
return cell;
}
运行效果:
三.两者对比了解代理模式
委托持有代理的引用,代理实现协议,委托通过代理得到代理服务。就比如你要找房子你要找一个阳光好的,价格少于1000元。房产中介能为你找房,它能提供很多的房源,有阳光好的少于1000的家电齐全等等,现在你们并没有什么关系,如果你想找房不可能呆在家里,于是你找了一家房产中介,这时你就成了委托方法,这时们就会签署一式两份的找房协议,上面有你的签名和中介的签名,你们各持有一份,这时你们就建立了委托代理的关系,这时你关系的不是中介提供的其他服务,你只关心签署协议中的条件。然后中介就会拿出符合条件的房源给你。这就是生活中的代理模式的例子。
上面只是一个简单的代理的生活抽象。把它映射到代码中又会是什么样了:
@protocol someDelegate<NSObject> //你们要签署的协议,这个协议是由你来提出
-(house*)getHouse; //要找的房子
@end
@interface some
@property (assign,nonautomic)id<someDelegate> delegate; //你去找了哪家的代理中介
@end
@interface agent()<someDelegate> //实现找房的协议
@end
@implement agent
-(house *)getHouse{
//找到符合条件的房子
return house;
}
@end
委托和代理建立联系,上面只是代码的设计。
运行时才是真实场景的存在:
some *you =[[some alloc]init]; //你出现了
agent *agent =[ [agen alloc]init] //房产中介出现了
上面两步委托和代理没有建立委托代理的关系
you.delegate = agent; //委托代理建立了关系,相当于签署了找房协议
[you.delegate getHouse] //这样你就能通过代理给你找到房子了。
运行时内存状态抽象图:
总结:代理模式随处可见,一般在MVC设计模式中,V(视图)层常常通过代理C(控制)层得到要显示的数据,并把用户对V(视图)层的操作传给C(控制)层,让C做相应的处理。如上中的UITableView (视图层) UIViewController(控制层),UITalbleView通过UIViewController的到数据,也可以把用户的操作传到UIViewController,所以任何的设计模式只要把它映射成C语言的数据和函数,就会更容易理解各种模式的设计原理。