1.Delegate的背景及使用场合
1.1背景:
分析 http://blog.csdn.net/sunnyboy9/article/details/16335301 里的实例 可知view离不开控制器, MJTgFooterView里面有 MJViewController *Controller这个属性 所以MJTgFooterView紧紧的依赖控制器,耦合性太强,假设控制器改变了,或者MJTgFooterView改变了,则整个系统都会挂掉,耦合性太强, 所以必须将其封装独立出来。
1.2Delegate的使用场合
对象A内部发生了一些事情,想通知对象B
对象B想监听对象A内部发生了什么事情
对象A想在自己的方法内部调用对象B的某个方法,并且对象A不能对对象B有耦合依赖
对象A想传递数据给对象B
对象B想监听对象A内部发生了什么事情
对象A想在自己的方法内部调用对象B的某个方法,并且对象A不能对对象B有耦合依赖
对象A想传递数据给对象B
2.使用delegate的步骤
先搞清楚谁是谁的代理(delegate)
定义代理协议,协议名称的命名规范:控件类名 + Delegate
定义代理方法
代理方法一般都定义为@optional
代理方法名都以控件名开头
代理方法至少有1个参数,将控件本身传递出去
设置代理(delegate)对象 (比如myView.delegate = xxxx;)
代理对象遵守协议
代理对象实现协议里面该实现的方法
在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情
(在调用之前判断代理是否实现了该代理方法)
……
以上情况,结果都一样:对象B是对象A的代理(delegate)
定义代理协议,协议名称的命名规范:控件类名 + Delegate
定义代理方法
代理方法一般都定义为@optional
代理方法名都以控件名开头
代理方法至少有1个参数,将控件本身传递出去
设置代理(delegate)对象 (比如myView.delegate = xxxx;)
代理对象遵守协议
代理对象实现协议里面该实现的方法
在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情
(在调用之前判断代理是否实现了该代理方法)
……
以上情况,结果都一样:对象B是对象A的代理(delegate)
3.MVC
MVC是一种设计思想,贯穿于整个iOS开发中,需要积累一定的项目经验,才能深刻体会其中的含义和好处
MVC中的三个角色
M:Model,模型数据
V:View,视图(界面)
C:Control,控制中心
MVC的几个明显的特征和体现:
View上面显示什么东西,取决于Model
只要Model数据改了,View的显示状态会跟着更改
Control负责初始化Model,并将Model传递给View去解析展示
MVC中的三个角色
M:Model,模型数据
V:View,视图(界面)
C:Control,控制中心
MVC的几个明显的特征和体现:
View上面显示什么东西,取决于Model
只要Model数据改了,View的显示状态会跟着更改
Control负责初始化Model,并将Model传递给View去解析展示
4.用代理实现下面效果
5.具体实现
5.1搭建界面
5.1.1(MJTgFooterView.xib
5.1.2MJTgCell.xib
5.2plist文件
5.3 代码实现
5.3.1模型类
//
// MJTg.h
#import <Foundation/Foundation.h>
@interface MJTg : NSObject
/**
* 标题
*/
@property (nonatomic, copy) NSString *title;
/**
* 价格
*/
@property (nonatomic, copy) NSString *price;
/**
* 图片
*/
@property (nonatomic, copy) NSString *icon;
/**
* 购买人数
*/
@property (nonatomic, copy) NSString *buyCount;
+ (instancetype)tgWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
//
// MJTg.m
#import "MJTg.h"
@implementation MJTg
+ (instancetype)tgWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
5.3.2用MJTgCell类封装MJTgCell.xib
//
// MJTgCell.h
#import <UIKit/UIKit.h>
@class MJTg;
@interface MJTgCell : UITableViewCell
/**
* 通过一个tableView来创建一个cell
*/
+ (instancetype)cellWithTableView:(UITableView *)tableView;
/**
* 团购模型
*/
@property (nonatomic, strong) MJTg *tg;
@end
//
// MJTgCell.m
#import "MJTgCell.h"
#import "MJTg.h"
@interface MJTgCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titleView;
@property (weak, nonatomic) IBOutlet UILabel *priceView;
@property (weak, nonatomic) IBOutlet UILabel *buyCountView;
@end
@implementation MJTgCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"tg";
MJTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
// 从xib中加载cell
cell = [[[NSBundle mainBundle] loadNibNamed:@"MJTgCell" owner:nil options:nil] lastObject];
}
return cell;
}
- (void)setTg:(MJTg *)tg
{
_tg = tg;
// 1.图片
self.iconView.image = [UIImage imageNamed:tg.icon];
// 2.标题
self.titleView.text = tg.title;
// 3.价格
self.priceView.text = [NSString stringWithFormat:@"¥%@", tg.price];
// 4.购买数
self.buyCountView.text = [NSString stringWithFormat:@"%@人已购买", tg.buyCount];
}
@end
5.3.3用MJTgFooterView类封装MJTgFooterView.xib
//
// MJTgFooterView.h
#import <UIKit/UIKit.h>
@class MJTgFooterView;
/**
1.协议名称: 控件类名 + Delegate
2.代理方法普遍都是@optional
3.
*/
@protocol MJTgFooterViewDelegate <NSObject>
@optional
- (void)tgFooterViewDidClickedLoadBtn:(MJTgFooterView *)tgFooterView;
@end
@interface MJTgFooterView : UIView
/**
* 快速创建一个footerView对象
*/
+ (instancetype)footerView;
@property (nonatomic, weak) id<MJTgFooterViewDelegate> delegate;
@end
//
// MJTgFooterView.m
#import "MJTgFooterView.h"
@interface MJTgFooterView()
- (IBAction)loadBtnClick;
@property (weak, nonatomic) IBOutlet UIButton *loadBtn;
@property (weak, nonatomic) IBOutlet UIView *loadingView;
@end
@implementation MJTgFooterView
+ (instancetype)footerView
{
return [[[NSBundle mainBundle] loadNibNamed:@"MJTgFooterView" owner:nil options:nil] lastObject];
}
/**
* 点击"加载"按钮
*/
- (IBAction)loadBtnClick {
// 1.隐藏加载按钮
self.loadBtn.hidden = YES;
// 2.显示"正在加载"
self.loadingView.hidden = NO;
// 3.显示更多的数据
// GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 3.0s后执行block里面的代码
// 通知代理
if ([self.delegate respondsToSelector:@selector(tgFooterViewDidClickedLoadBtn:)]) {
[self.delegate tgFooterViewDidClickedLoadBtn:self];
}
// 4.显示加载按钮
self.loadBtn.hidden = NO;
// 5.隐藏"正在加载"
self.loadingView.hidden = YES;
});
}
@end
5.4控制器
//
// MJViewController.m
#import "MJViewController.h"
#import "MJTg.h"
#import "MJTgCell.h"
#import "MJTgFooterView.h"
#import "MJTgHeaderView.h"
@interface MJViewController () <UITableViewDataSource, MJTgFooterViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *tgs;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 设置每一行cell的高度
self.tableView.rowHeight = 80;
// 设置footerView
MJTgFooterView *footer = [MJTgFooterView footerView];
footer.delegate = self;
self.tableView.tableFooterView = footer;
// 设置headerView
self.tableView.tableHeaderView = [MJTgHeaderView headerView];
// 设置tableView尾部显示的控件(tableFooterView的宽度永远是tableView的宽度)
// tableFooterView只需要设置高度
// UIButton *footerBtn = [UIButton buttonWithType:UIButtonTypeSystem];
// footerBtn.frame = CGRectMake(0, 0, 0, 35);
// footerBtn.backgroundColor = [UIColor orangeColor];
// [footerBtn setTitle:@"加载更多团购" forState:UIControlStateNormal];
// UINib *nib = [UINib nibWithNibName:@"MJTgFooterView" bundle:[NSBundle mainBundle]];
// 创建nib对象
// UINib *nib = [UINib nibWithNibName:@"MJTgFooterView" bundle:nil];
//
// // 加载xib\nib
// UIView *footerView = [[nib instantiateWithOwner:nil options:nil] lastObject];
// self.tableView.tableFooterView = footerView;
}
#pragma mark - MJTgFooterViewDelegate方法
/**
* 加载更多的数据
*/
- (void)tgFooterViewDidClickedLoadBtn:(MJTgFooterView *)tgFooterView
{
#warning 正常开发:发送网络请求给远程的服务器
// 1.添加更多的模型数据
MJTg *tg = [[MJTg alloc] init];
tg.icon = @"ad_01";
tg.title = @"新增加的团购数据..";
tg.price = @"100";
tg.buyCount = @"0";
[self.tgs addObject:tg];
// 2.刷新表格(告诉tableView重新加载模型数据, 调用tableView的reloadData)
[self.tableView reloadData];
}
/**
* 隐藏状态栏
*/
- (BOOL)prefersStatusBarHidden
{
return YES;
}
/**
* 数据的懒加载
*/
- (NSMutableArray *)tgs
{
if (_tgs == nil) {
// 初始化
// 1.获得plist的全路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"tgs.plist" ofType:nil];
// 2.加载数组
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
// 3.将dictArray里面的所有字典转成模型对象,放到新的数组中
NSMutableArray *tgArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
// 3.1.创建模型对象
MJTg *tg = [MJTg tgWithDict:dict];
// 3.2.添加模型对象到数组中
[tgArray addObject:tg];
}
// 4.赋值
_tgs = tgArray;
}
return _tgs;
}
#pragma mark - 数据源方法
/**
* 一共有多少行数据
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tgs.count;
}
/**
* 每一行显示怎样的cell
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
MJTgCell *cell = [MJTgCell cellWithTableView:tableView];
// 2.给cell传递模型数据
cell.tg = self.tgs[indexPath.row];
return cell;
}
@end
6.总结
这样使用代理设计模式完成上面的软件,则假设哪天控制器变化对view没有任何影响,从而实现了封装。