代理、通知、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]; }