代理、通知、KVO的应用

实现下图效果,每点击一次cell的“加号”或者“减号”,就可以让“底部view”的总价进行对应的增加或者减少。

下图是实际运行效果图:

           图(1)

因为“底部UIView”需要一直显示在底部。如果把底部UIView添加到tableView上会导致其跟随tableView的滚动而滚动,所以不能把底部UIView作为tableView的子控件。所以把底部UIView添加到控制器的view上,让底部的UIView和tableView同级。如下图2展示了视图层级结构:

 

 

                   图(1)

方案一:KVO实现:

控制器监听数据模型中count属性的变化,进而根据count的增减做出不同的操作

步骤:

1.添加KVO监听

2.监听到键值变化后的操作

3.移除KVO监听

#import "ViewController.h"
#import "XMGWineCell.h"
#import "XMGWine.h"
#import "MJExtension.h"

@interface ViewController () <UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UIButton *buyButton;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
/** 酒数据 */
@property (nonatomic, strong) NSArray *wineArray;
/** 总价 */
@property (weak, nonatomic) IBOutlet UILabel *totalPriceLabel;
@end

@implementation ViewController
- (NSArray *)wineArray
{
    if (!_wineArray) {
        self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
        
        for (XMGWine *wine in self.wineArray) {
            // 添加KVO监听
            [wine addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
        }
    }
    return _wineArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
}
#pragma mark - 移除KVO监听
- (void)dealloc
{
    for (XMGWine *wine in self.wineArray) {
        [wine removeObserver:self forKeyPath:@"count"];
    }
}

#pragma mark - KVO监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(XMGWine *)wine change:(NSDictionary *)change context:(void *)context
{
    // NSKeyValueChangeNewKey == @"new"
    int new = [change[NSKeyValueChangeNewKey] intValue];
    // NSKeyValueChangeOldKey == @"old"
    int old = [change[NSKeyValueChangeOldKey] intValue];
    
    if (new > old) { // 增加数量
        int totalPrice = self.totalPriceLabel.text.intValue + wine.money.intValue;
        self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
        self.buyButton.enabled = YES;
    } else { // 数量减小
        int totalPrice = self.totalPriceLabel.text.intValue - wine.money.intValue;
        self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
        self.buyButton.enabled = totalPrice > 0;
    }
}

方案二:通知:

步骤:

1.注册通知

2.添加监听

3.移除通知

1.在自定义cell的.m文件中注册通知:

#import "XMGWineCell.h"
#import "XMGWine.h"
#import "XMGCircleButton.h"

@interface XMGWineCell()
@property (weak, nonatomic) IBOutlet XMGCircleButton *minusButton;
@property (weak, nonatomic) IBOutlet UIImageView *imageImageView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UILabel *moneyLabel;
@property (weak, nonatomic) IBOutlet UILabel *countLabel;
@end

@implementation XMGWineCell

- (void)setWine:(XMGWine *)wine
{
    _wine = wine;
    
    self.imageImageView.image = [UIImage imageNamed:wine.image];
    self.nameLabel.text = wine.name;
    self.moneyLabel.text = wine.money;
    self.countLabel.text = [NSString stringWithFormat:@"%d", wine.count];
    self.minusButton.enabled = (wine.count > 0);
}

/**
 *  加号点击
 */
- (IBAction)plusClick {
    // 修改模型
    self.wine.count++;
    
    // 修改数量label
    self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
    
    // 减号能点击
    self.minusButton.enabled = YES;
    
    // 发布通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"plusClickNotification" object:self];
}

/**
 *  减号点击
 */
- (IBAction)minusClick {
    // 修改模型
    self.wine.count--;
    
    // 修改数量label
    self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
    
    // 减号按钮不能点击
    if (self.wine.count == 0) {
        self.minusButton.enabled = NO;
    }
    
    // 发布通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"minusClickNotification" object:self];
}
@end

2.在控制器的.m文件中添加监听(在通知中心注册监听)

3.在控制器的dealloc方法中移除监听

#import "ViewController.h"
#import "XMGWineCell.h"
#import "XMGWine.h"
#import "MJExtension.h"

@interface ViewController () <UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UIButton *buyButton;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
/** 酒数据 */
@property (nonatomic, strong) NSArray *wineArray;
/** 总价 */
@property (weak, nonatomic) IBOutlet UILabel *totalPriceLabel;
@end

@implementation ViewController
- (NSArray *)wineArray
{
    if (!_wineArray) {
        self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
    }
    return _wineArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 监听通知
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(plusClick:) name:@"plusClickNotification" object:nil];
    [center addObserver:self selector:@selector(minusClick:) name:@"minusClickNotification" object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - 按钮点击
- (IBAction)clear {
    self.totalPriceLabel.text = @"0";
    
    // 将模型里面的count清零
    for (XMGWine *wine in self.wineArray) {
        wine.count = 0;
    }
    
    // 刷新
    [self.tableView reloadData];
    
    self.buyButton.enabled = NO;
}

- (IBAction)buy {
    // 打印出所有要买的东西
    for (XMGWine *wine in self.wineArray) {
        if (wine.count) {
            NSLog(@"%d件【%@】", wine.count, wine.name);
        }
    }
}

#pragma mark - 监听通知
- (void)plusClick:(NSNotification *)note
{
    self.buyButton.enabled = YES;
    
    // 取出cell(通知的发布者)
    XMGWineCell *cell = note.object;
    // 计算总价
    int totalPrice = self.totalPriceLabel.text.intValue + cell.wine.money.intValue;
    // 设置总价
    self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
}

- (void)minusClick:(NSNotification *)note
{
    // 取出cell(通知的发布者)
    XMGWineCell *cell = note.object;
    // 计算总价
    int totalPrice = self.totalPriceLabel.text.intValue - cell.wine.money.intValue;
    // 设置总价
    self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    
    self.buyButton.enabled = totalPrice > 0;
}

 

方案三:delegate:

步骤:

1.制定代理协议

2.设置代理属性

3.遵守协议,实现代理方法

4.调用代理实现的协议方法

1.制定代理协议

2.设置代理属性

#import <UIKit/UIKit.h>
@class XMGWine, XMGCircleButton, XMGWineCell;

@protocol XMGWineCellDelegate <NSObject>
@optional
- (void)wineCellDidClickPlusButton:(XMGWineCell *)wineCell;
- (void)wineCellDidClickMinusButton:(XMGWineCell *)wineCell;
@end

@interface XMGWineCell : UITableViewCell
@property (strong, nonatomic) XMGWine *wine;

/** 代理对象 */
@property (nonatomic, weak) id<XMGWineCellDelegate> delegate;
@end

自定义cell的.m文件中判断代理是否响应协议方法,如果响应,则调用代理实现的协议方法。

/**
 *  加号点击
 */
- (IBAction)plusClick {
    // 修改模型
    self.wine.count++;
    
    // 修改数量label
    self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
    
    // 减号能点击
    self.minusButton.enabled = YES;
    
    // 通知代理(调用代理的方法)
    // respondsToSelector:能判断某个对象是否实现了某个方法
    if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
        [self.delegate wineCellDidClickPlusButton:self];
    }
}

/**
 *  减号点击
 */
- (IBAction)minusClick {
    // 修改模型
    self.wine.count--;
    
    // 修改数量label
    self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
    
    // 减号按钮不能点击
    if (self.wine.count == 0) {
        self.minusButton.enabled = NO;
    }
    
    // 通知代理(调用代理的方法)
    if ([self.delegate respondsToSelector:@selector(wineCellDidClickMinusButton:)]) {
        [self.delegate wineCellDidClickMinusButton:self];
    }
}

3.控制器的.m文件中遵守代理协议,实现协议方法

#import "ViewController.h"
#import "XMGWineCell.h"
#import "XMGWine.h"
#import "MJExtension.h"

@interface ViewController () <UITableViewDataSource, XMGWineCellDelegate, UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UIButton *buyButton;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
/** 酒数据 */
@property (nonatomic, strong) NSArray *wineArray;
/** 总价 */
@property (weak, nonatomic) IBOutlet UILabel *totalPriceLabel;

/** 购物车对象(存放需要购买的商品) */
@property (nonatomic, strong) NSMutableArray *wineCar;
@end

@implementation ViewController
- (NSMutableArray *)wineCar
{
    if (!_wineCar) {
        _wineCar = [NSMutableArray array];
    }
    return _wineCar;
}

- (NSArray *)wineArray
{
    if (!_wineArray) {
        self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
    }
    return _wineArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
}

#pragma mark - <XMGWineCellDelegate>
- (void)wineCellDidClickMinusButton:(XMGWineCell *)wineCell
{
    // 计算总价
    int totalPrice = self.totalPriceLabel.text.intValue - wineCell.wine.money.intValue;
    
    // 设置总价
    self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    
    self.buyButton.enabled = totalPrice > 0;
    
    // 将商品从购物车中移除
    if (wineCell.wine.count == 0) {
        [self.wineCar removeObject:wineCell.wine];
    }
}

- (void)wineCellDidClickPlusButton:(XMGWineCell *)wineCell
{
    // 计算总价
    int totalPrice = self.totalPriceLabel.text.intValue + wineCell.wine.money.intValue;
    
    // 设置总价
    self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    
    self.buyButton.enabled = YES;
    
    // 如果这个商品已经在购物车中,就不用再添加
    if ([self.wineCar containsObject:wineCell.wine]) return;
    
    // 添加需要购买的商品
    [self.wineCar addObject:wineCell.wine];
}

 

posted @ 2015-10-16 01:10  oneSong  阅读(284)  评论(0编辑  收藏  举报