您的位置:首页 > 其它

用代理设计模式实现团购界面

2013-11-15 09:39 549 查看

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

2.使用delegate的步骤

先搞清楚谁是谁的代理(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去解析展示

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没有任何影响,从而实现了封装。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: