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

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值