zoukankan      html  css  js  c++  java
  • iOS开发——UI进阶篇(五)通知、代理、kvo的应用和对比,购物车

    一、通知


    1、通知中心(NSNotificationCenter)
    每一个应用程序都有一个通知中心(NSNotificationCenter)实例,专门负责协助不同对象之间的消息通信
    任何一个对象都可以向通知中心发布通知(NSNotification),描述自己在做什么。其他感兴趣的对象(Observer)可以申请在某个特定通知发布时(或在某个特定的对象发布通知时)收到这个通知

    2、通知(NSNotification)
    一个完整的通知一般包含3个属性:
    - (NSString *)name; // 通知的名称
    - (id)object; // 通知发布者(是谁要发布通知)
    - (NSDictionary *)userInfo; // 一些额外的信息(通知发布者传递给通知接收者的信息内容)

    初始化一个通知(NSNotification)对象
    + (instancetype)notificationWithName:(NSString *)aName object:(id)anObject;
    + (instancetype)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
    - (instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;

    3、发布通知
    通知中心(NSNotificationCenter)提供了相应的方法来帮助发布通知
    - (void)postNotification:(NSNotification *)notification;
    发布一个notification通知,可在notification对象中设置通知的名称、通知发布者、额外信息等

    - (void)postNotificationName:(NSString *)aName object:(id)anObject;
    发布一个名称为aName的通知,anObject为这个通知的发布者

    - (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
    发布一个名称为aName的通知,anObject为这个通知的发布者,aUserInfo为额外信息

    4、注册通知监听器
    通知中心(NSNotificationCenter)提供了方法来注册一个监听通知的监听器(Observer)
    - (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
    observer:监听器,即谁要接收这个通知
    aSelector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入
    aName:通知的名称。如果为nil,那么无论通知的名称是什么,监听器都能收到这个通知
    anObject:通知发布者。如果为anObject和aName都为nil,监听器都收到所有的通知

    - (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;
    name:通知的名称
    obj:通知发布者
    block:收到对应的通知时,会回调这个block
    queue:决定了block在哪个操作队列中执行,如果传nil,默认在当前操作队列中同步执行

    5、取消注册通知监听器
    通知中心不会保留(retain)监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃

    通知中心提供了相应的方法来取消注册监听器
    - (void)removeObserver:(id)observer;
    - (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;

    一般在监听器销毁之前取消注册(如在监听器中加入下列代码):

    - (void)dealloc {
    //[super dealloc]; 非ARC中需要调用此句
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    }

    6、UIDevice通知
    UIDevice类提供了一个单粒对象,它代表着设备,通过它可以获得一些设备相关的信息,比如电池电量值(batteryLevel)、电池状态(batteryState)、设备的类型(model,比如iPod、iPhone等)、设备的系统(systemVersion)

    通过[UIDevice currentDevice]可以获取这个单粒对象

    UIDevice对象会不间断地发布一些通知,下列是UIDevice对象所发布通知的名称常量:
    UIDeviceOrientationDidChangeNotification // 设备旋转
    UIDeviceBatteryStateDidChangeNotification // 电池状态改变
    UIDeviceBatteryLevelDidChangeNotification // 电池电量改变
    UIDeviceProximityStateDidChangeNotification // 近距离传感器(比如设备贴近了使用者的脸部)

    7、键盘通知
    我们经常需要在键盘弹出或者隐藏的时候做一些特定的操作,因此需要监听键盘的状态

    键盘状态改变的时候,系统会发出一些特定的通知
    UIKeyboardWillShowNotification // 键盘即将显示
    UIKeyboardDidShowNotification // 键盘显示完毕
    UIKeyboardWillHideNotification // 键盘即将隐藏
    UIKeyboardDidHideNotification // 键盘隐藏完毕
    UIKeyboardWillChangeFrameNotification // 键盘的位置尺寸即将发生改变
    UIKeyboardDidChangeFrameNotification // 键盘的位置尺寸改变完毕

    系统发出键盘通知时,会附带一下跟键盘有关的额外信息(字典),字典常见的key如下:
    UIKeyboardFrameBeginUserInfoKey // 键盘刚开始的frame
    UIKeyboardFrameEndUserInfoKey // 键盘最终的frame(动画执行完毕后)
    UIKeyboardAnimationDurationUserInfoKey // 键盘动画的时间
    UIKeyboardAnimationCurveUserInfoKey // 键盘动画的执行节奏(快慢)

    下面通过购物车案例了解通知、代理以及kvo的使用

    二、通知


    cell内部:

       // 发布通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"plusClickNotification" object:self];
        // 发布通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"minusClickNotification" object:self];

    控制器中:

    // 注册通知监听器
          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)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;
    }

    全代码:

      1 /****************** XMGWine*********************/
      2 #import <Foundation/Foundation.h>
      3 
      4 @interface XMGWine : NSObject
      5 @property (copy, nonatomic) NSString *money;
      6 @property (copy, nonatomic) NSString *name;
      7 @property (copy, nonatomic) NSString *image;
      8 
      9 /** 数量 */
     10 @property (nonatomic, assign) int count;
     11 @end
     12 
     13 #import "XMGWine.h"
     14 
     15 @implementation XMGWine
     16 
     17 @end
     18 
     19 /***************** XMGCircleButton*****************/
     20 #import <UIKit/UIKit.h>
     21 
     22 @interface XMGCircleButton : UIButton
     23 
     24 @end
     25 
     26 #import "XMGCircleButton.h"
     27 
     28 @implementation XMGCircleButton
     29 
     30 - (void)awakeFromNib
     31 {
     32     // 设置边框颜色
     33     self.layer.borderColor = [UIColor redColor].CGColor;
     34     // 设置边框宽度
     35     self.layer.borderWidth = 1;
     36     // 设置圆角半径
     37     self.layer.cornerRadius = self.frame.size.width * 0.5;
     38 }
     39 
     40 @end
     41 
     42 /****************** XMGWineCell*********************/
     43 #import <UIKit/UIKit.h>
     44 @class XMGWine, XMGCircleButton;
     45 
     46 @interface XMGWineCell : UITableViewCell
     47 @property (strong, nonatomic) XMGWine *wine;
     48 @end
     49 
     50 #import "XMGWineCell.h"
     51 #import "XMGWine.h"
     52 #import "XMGCircleButton.h"
     53 
     54 @interface XMGWineCell()
     55 @property (weak, nonatomic) IBOutlet XMGCircleButton *minusButton;
     56 @property (weak, nonatomic) IBOutlet UIImageView *imageImageView;
     57 @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
     58 @property (weak, nonatomic) IBOutlet UILabel *moneyLabel;
     59 @property (weak, nonatomic) IBOutlet UILabel *countLabel;
     60 @end
     61 
     62 @implementation XMGWineCell
     63 
     64 - (void)setWine:(XMGWine *)wine
     65 {
     66     _wine = wine;
     67     
     68     self.imageImageView.image = [UIImage imageNamed:wine.image];
     69     self.nameLabel.text = wine.name;
     70     self.moneyLabel.text = wine.money;
     71     self.countLabel.text = [NSString stringWithFormat:@"%d", wine.count];
     72     self.minusButton.enabled = (wine.count > 0);
     73 }
     74 
     75 /**
     76  *  加号点击
     77  */
     78 - (IBAction)plusClick {
     79     // 修改模型
     80     self.wine.count++;
     81     
     82     // 修改数量label
     83     self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
     84     
     85     // 减号能点击
     86     self.minusButton.enabled = YES;
     87     
     88     // 发布通知
     89     [[NSNotificationCenter defaultCenter] postNotificationName:@"plusClickNotification" object:self];
     90 }
     91 
     92 /**
     93  *  减号点击
     94  */
     95 - (IBAction)minusClick {
     96     // 修改模型
     97     self.wine.count--;
     98     
     99     // 修改数量label
    100     self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
    101     
    102     // 减号按钮不能点击
    103     if (self.wine.count == 0) {
    104         self.minusButton.enabled = NO;
    105     }
    106     
    107     // 发布通知
    108     [[NSNotificationCenter defaultCenter] postNotificationName:@"minusClickNotification" object:self];
    109 }
    110 @end
    111 
    112 /****************** ViewController*********************/
    113 #import <UIKit/UIKit.h>
    114 
    115 @interface ViewController : UIViewController
    116 @end
    117 
    118 #import "ViewController.h"
    119 #import "XMGWineCell.h"
    120 #import "XMGWine.h"
    121 #import "MJExtension.h"
    122 
    123 @interface ViewController () <UITableViewDataSource>
    124 @property (weak, nonatomic) IBOutlet UIButton *buyButton;
    125 @property (weak, nonatomic) IBOutlet UITableView *tableView;
    126 /** 酒数据 */
    127 @property (nonatomic, strong) NSArray *wineArray;
    128 /** 总价 */
    129 @property (weak, nonatomic) IBOutlet UILabel *totalPriceLabel;
    130 @end
    131 
    132 @implementation ViewController
    133 - (NSArray *)wineArray
    134 {
    135     if (!_wineArray) {
    136         self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
    137     }
    138     return _wineArray;
    139 }
    140 
    141 - (void)viewDidLoad {
    142     [super viewDidLoad];
    143     
    144     // 监听通知
    145     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    146     [center addObserver:self selector:@selector(plusClick:) name:@"plusClickNotification" object:nil];
    147     [center addObserver:self selector:@selector(minusClick:) name:@"minusClickNotification" object:nil];
    148 }
    149 
    150 - (void)dealloc
    151 {
    152     [[NSNotificationCenter defaultCenter] removeObserver:self];
    153 }
    154 
    155 #pragma mark - 按钮点击
    156 - (IBAction)clear {
    157     self.totalPriceLabel.text = @"0";
    158     
    159     // 将模型里面的count清零
    160     for (XMGWine *wine in self.wineArray) {
    161         wine.count = 0;
    162     }
    163     
    164     // 刷新
    165     [self.tableView reloadData];
    166     
    167     self.buyButton.enabled = NO;
    168 }
    169 
    170 - (IBAction)buy {
    171     // 打印出所有要买的东西
    172     for (XMGWine *wine in self.wineArray) {
    173         if (wine.count) {
    174             NSLog(@"%d件【%@】", wine.count, wine.name);
    175         }
    176     }
    177 }
    178 
    179 #pragma mark - 监听通知
    180 - (void)plusClick:(NSNotification *)note
    181 {
    182     self.buyButton.enabled = YES;
    183     
    184     // 取出cell(通知的发布者)
    185     XMGWineCell *cell = note.object;
    186     // 计算总价
    187     int totalPrice = self.totalPriceLabel.text.intValue + cell.wine.money.intValue;
    188     // 设置总价
    189     self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    190 }
    191 
    192 - (void)minusClick:(NSNotification *)note
    193 {
    194     // 取出cell(通知的发布者)
    195     XMGWineCell *cell = note.object;
    196     // 计算总价
    197     int totalPrice = self.totalPriceLabel.text.intValue - cell.wine.money.intValue;
    198     // 设置总价
    199     self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    200     
    201     self.buyButton.enabled = totalPrice > 0;
    202 }
    203 
    204 #pragma mark - <UITableViewDataSource>
    205 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    206 {
    207     return self.wineArray.count;
    208 }
    209 
    210 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    211 {
    212     static NSString *ID = @"wine";
    213     XMGWineCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    214     
    215     cell.wine = self.wineArray[indexPath.row];
    216     
    217     return cell;
    218 }
    219 
    220 @end
    购物车(通知)

    Main.storyboard

    三、代理


    这是我总结的关于协议和代理

     

    这里有两句话写错了,应该是“要想其他对象成为我的代理,必须先遵守我的协议” 

    cell.delegate = self; // 设置控制器为cell的代理

    @interface ViewController () <UITableViewDataSource, XMGWineCellDelegate, UITableViewDelegate> // 控制器必须先遵守cell的协议

    这就相当于设置TableView(TableView.delegate = self)的代理为控制器时,控制器也要遵守<UITableViewDelegate>这个协议

    依次类推,dog对象,cat对象,person对象,任何对象想成为我的代理,都必须遵守我的协议

    那么在这个例子中

    cell内部:

    // 通知代理(调用代理的方法)
        // respondsToSelector:能判断某个对象是否实现了某个方法
        if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
            [self.delegate wineCellDidClickPlusButton:self];
        }
    
    // 通知代理(调用代理的方法)
        if ([self.delegate respondsToSelector:@selector(wineCellDidClickMinusButton:)]) {
            [self.delegate wineCellDidClickMinusButton:self];
        }

    控制器:

    #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];
    }

    这样通过通知代理,调用代理方法来实现点击加号减号按钮时计算总价

    部分代码:

      1 /****************** XMGWineCell.h****************/
      2 #import <UIKit/UIKit.h>
      3 @class XMGWine, XMGCircleButton, XMGWineCell;
      4 
      5 @protocol XMGWineCellDelegate <NSObject>
      6 @optional
      7 - (void)wineCellDidClickPlusButton:(XMGWineCell *)wineCell;
      8 - (void)wineCellDidClickMinusButton:(XMGWineCell *)wineCell;
      9 @end
     10 
     11 @interface XMGWineCell : UITableViewCell
     12 @property (strong, nonatomic) XMGWine *wine;
     13 
     14 /** 代理对象 */
     15 @property (nonatomic, weak) id<XMGWineCellDelegate> delegate;
     16 @end
     17 
     18 
     19 /****************** XMGWineCell.m****************/
     20 
     21 #import "XMGWineCell.h"
     22 #import "XMGWine.h"
     23 #import "XMGCircleButton.h"
     24 
     25 @interface XMGWineCell()
     26 @property (weak, nonatomic) IBOutlet XMGCircleButton *minusButton;
     27 @property (weak, nonatomic) IBOutlet UIImageView *imageImageView;
     28 @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
     29 @property (weak, nonatomic) IBOutlet UILabel *moneyLabel;
     30 @property (weak, nonatomic) IBOutlet UILabel *countLabel;
     31 @end
     32 
     33 @implementation XMGWineCell
     34 
     35 - (void)setWine:(XMGWine *)wine
     36 {
     37     _wine = wine;
     38     
     39     self.imageImageView.image = [UIImage imageNamed:wine.image];
     40     self.nameLabel.text = wine.name;
     41     self.moneyLabel.text = wine.money;
     42     self.countLabel.text = [NSString stringWithFormat:@"%d", wine.count];
     43     self.minusButton.enabled = (wine.count > 0);
     44 }
     45 
     46 /**
     47  *  加号点击
     48  */
     49 - (IBAction)plusClick {
     50     // 修改模型
     51     self.wine.count++;
     52     
     53     // 修改数量label
     54     self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
     55     
     56     // 减号能点击
     57     self.minusButton.enabled = YES;
     58     
     59     // 通知代理(调用代理的方法)
     60     // respondsToSelector:能判断某个对象是否实现了某个方法
     61     if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
     62         [self.delegate wineCellDidClickPlusButton:self];
     63     }
     64 }
     65 
     66 /**
     67  *  减号点击
     68  */
     69 - (IBAction)minusClick {
     70     // 修改模型
     71     self.wine.count--;
     72     
     73     // 修改数量label
     74     self.countLabel.text = [NSString stringWithFormat:@"%d", self.wine.count];
     75     
     76     // 减号按钮不能点击
     77     if (self.wine.count == 0) {
     78         self.minusButton.enabled = NO;
     79     }
     80     
     81     // 通知代理(调用代理的方法)
     82     if ([self.delegate respondsToSelector:@selector(wineCellDidClickMinusButton:)]) {
     83         [self.delegate wineCellDidClickMinusButton:self];
     84     }
     85 }
     86 @end
     87 
     88 /****************** ViewController****************/
     89 #import "ViewController.h"
     90 #import "XMGWineCell.h"
     91 #import "XMGWine.h"
     92 #import "MJExtension.h"
     93 
     94 @interface ViewController () <UITableViewDataSource, XMGWineCellDelegate, UITableViewDelegate>
     95 @property (weak, nonatomic) IBOutlet UIButton *buyButton;
     96 @property (weak, nonatomic) IBOutlet UITableView *tableView;
     97 /** 酒数据 */
     98 @property (nonatomic, strong) NSArray *wineArray;
     99 /** 总价 */
    100 @property (weak, nonatomic) IBOutlet UILabel *totalPriceLabel;
    101 
    102 /** 购物车对象(存放需要购买的商品) */
    103 @property (nonatomic, strong) NSMutableArray *wineCar;
    104 @end
    105 
    106 @implementation ViewController
    107 - (NSMutableArray *)wineCar
    108 {
    109     if (!_wineCar) {
    110         _wineCar = [NSMutableArray array];
    111     }
    112     return _wineCar;
    113 }
    114 
    115 - (NSArray *)wineArray
    116 {
    117     if (!_wineArray) {
    118         self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
    119     }
    120     return _wineArray;
    121 }
    122 
    123 - (void)viewDidLoad {
    124     [super viewDidLoad];
    125     
    126     
    127 }
    128 
    129 #pragma mark - <XMGWineCellDelegate>
    130 - (void)wineCellDidClickMinusButton:(XMGWineCell *)wineCell
    131 {
    132     // 计算总价
    133     int totalPrice = self.totalPriceLabel.text.intValue - wineCell.wine.money.intValue;
    134     
    135     // 设置总价
    136     self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    137     
    138     self.buyButton.enabled = totalPrice > 0;
    139     
    140     // 将商品从购物车中移除
    141     if (wineCell.wine.count == 0) {
    142         [self.wineCar removeObject:wineCell.wine];
    143     }
    144 }
    145 
    146 - (void)wineCellDidClickPlusButton:(XMGWineCell *)wineCell
    147 {
    148     // 计算总价
    149     int totalPrice = self.totalPriceLabel.text.intValue + wineCell.wine.money.intValue;
    150     
    151     // 设置总价
    152     self.totalPriceLabel.text = [NSString stringWithFormat:@"%d", totalPrice];
    153     
    154     self.buyButton.enabled = YES;
    155     
    156     // 如果这个商品已经在购物车中,就不用再添加
    157     if ([self.wineCar containsObject:wineCell.wine]) return;
    158     
    159     // 添加需要购买的商品
    160     [self.wineCar addObject:wineCell.wine];
    161 }
    162 
    163 #pragma mark - 按钮点击
    164 - (IBAction)clear {
    165     // 将模型里面的count清零
    166     for (XMGWine *wine in self.wineCar) {
    167         wine.count = 0;
    168     }
    169     
    170     // 刷新
    171     [self.tableView reloadData];
    172     
    173     // 清空购物车数据
    174     [self.wineCar removeAllObjects];
    175     
    176     self.buyButton.enabled = NO;
    177     self.totalPriceLabel.text = @"0";
    178 }
    179 
    180 - (IBAction)buy {
    181     // 打印出所有要买的东西
    182     for (XMGWine *wine in self.wineCar) {
    183         NSLog(@"%d件【%@】", wine.count, wine.name);
    184     }
    185 }
    186 
    187 #pragma mark - <UITableViewDataSource>
    188 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    189 {
    190     return self.wineArray.count;
    191 }
    192 
    193 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    194 {
    195     static NSString *ID = @"wine";
    196     XMGWineCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    197     
    198     cell.delegate = self;
    199     cell.wine = self.wineArray[indexPath.row];
    200     
    201     return cell;
    202 }
    203 
    204 @end
    购物车(代理)

    四、KVO


    关于kvo的介绍在前面有一章节专门讲过,那这里就不多说了

    懒加载时添加监听

    - (NSArray *)wineArray
    {
        if (!_wineArray) {
            self.wineArray = [XMGWine objectArrayWithFilename:@"wine.plist"];
            
            // 添加监听 监听count这个属性值的变化
            for (XMGWine *wine in self.wineArray) {
                [wine addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
            }
        }
        return _wineArray;
    }

    只要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;
        }
    }

    五、代理、通知、KVO对比


    1、 通知(NSNotificationCenterNSNotification)
      任何对象之间都可以传递消息
      使用范围:
        1个对象可以发通知给N个对象
        1个对象可以接受N个对象发出的通知

      缺点:
        必须得保证通知的名字在发出和监听时是一致的


    2、 KVO
      仅仅是能监听对象属性的改变(灵活度不如通知和代理)


    3、 代理
      使用范围
        1个对象只能设置一个代理(假设这个对象只有1个代理属性)
        1个对象能成为多个对象的代理
      比`通知`规范(包括命名规范、利用程序员之间的交流)
      建议使用`代理`多于`通知`

    将来的你会感谢今天如此努力的你! 版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    shell test用法
    Makefile debug的经验
    Makefile 中:= ?= += =的区别
    Makefile中常用的函数
    Makefile选项CFLAGS,LDFLAGS,LIBS
    makefile双冒号规则
    makefile中的伪目标,强制目标和双冒号规则
    makefile 使用环境变量
    linux shell if语句使用方法
    linux的test命令
  • 原文地址:https://www.cnblogs.com/chglog/p/4676905.html
Copyright © 2011-2022 走看看