iOS —— 初识KVO

04-01 阅读 0评论

iOS —— 初始KVO

  • KVO的基础
    • 1. KVO概念
    • 2. KVO使用步骤
      • 注册KVO监听
      • 实现KVO监听
      • 销毁KVO监听
      • 3. KVO基本用法
      • 4. KVO传值
      • 禁止KVO的方法
      • 注意事项:

        KVO的基础

        1. KVO概念

        KVO是一种开发模式,它的全称是Key-Value Observing (观察者模式) 是苹果Fundation框架下提供的一种开发机制,使用KVO,可以方便地对指定对象的某个属性进行观察,当属性发生变化时,进行通知,告诉开发者属性旧值和新值对应的内容。

        iOS —— 初识KVO,iOS —— 初识KVO,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,注册,第1张
        (图片来源网络,侵删)

        2. KVO使用步骤

        注册KVO监听

        通过[addObserver:forKeyPath:options:context:]方法注册KVO,这样可以接收到keyPath属性的变化事件;

        • observer:观察者,监听属性变化的对象。该对象必须实现observeValueForKeyPath:ofObject:change:context: 方法。
        • keyPath:要观察的属性名称。要和属性声明的名称一致。
        • options:回调方法中收到被观察者的属性的旧值或新值等,对KVO机制进行配置,修改KVO通知的时机以及通知的内容。
        • context:传入任意类型的对象,在"接收消息回调"的代码中可以接收到这个对象,是KVO中的一种传值方式。

          实现KVO监听

          通过方法[observeValueForKeyPath:ofObject:change:context:]实现KVO的监听;

          • keyPath:被观察对象的属性。
          • object:被观察的对象。
          • change:字典,存放相关的值,根据options传入的枚举来返回新值旧值。
          • context:注册观察者的时候,context传递过来的值。

            销毁KVO监听

            在不需要监听的时候,通过方法**[removeObserver:forKeyPath:],**移除监听。

            3. KVO基本用法

            我们可以通过对button的背景颜色进行监听,当背景颜色改变的时候,分别打印出背景颜色的前后变化的数值。

            self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
                self.button.frame = CGRectMake(150, 150, 100, 100);
                self.button.backgroundColor = UIColor.yellowColor;
                [self.view addSubview:self.button];
                
                [self.button addTarget:self action:@selector(press:) forControlEvents:UIControlEventTouchUpInside];
                
                [self.button addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
            
            - (void)press {
                //改变被监听对象的值
                [self.kvoButton setValue:[UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 250 / 250.0 alpha:1] forKey:@"backgroundColor"];
            }
            
            //当属性变化时会激发该监听方法
            - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
                //打印监听结果
                if ([keyPath isEqual:@"backgroundColor"]) {
                    NSLog(@"old value is: %@", [change objectForKey:@"old"]);
                    NSLog(@"new value is: %@", [change objectForKey:@"new"]);
                }
            }
            

            我们点击一次button:

            iOS —— 初识KVO

            iOS —— 初识KVO,iOS —— 初识KVO,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,注册,第3张
            (图片来源网络,侵删)

            4. KVO传值

            KVO传值也很简单,可以理解为我们对第二个viewController的某一个属性做一个监听,当我们跳转到第一个viewController的时候就可以监听到值的改变。KVO传值也很简单,可以理解为我们对第二个viewController的某一个属性做一个监听,当我们跳转到第一个viewController的时候就可以监听到值的改变。

            //第一个视图部分
            - (void)viewDidLoad {
                [super viewDidLoad];
                // Do any additional setup after loading the view.
                
                
                self.label = [[UILabel alloc] init];
                self.label.text = @"还没传值";
                self.label.frame = CGRectMake(150, 300, 100, 25);
                
                self.button = [UIButton buttonWithType:UIButtonTypeCustom];
                self.button.frame = CGRectMake(150, 150, 100, 100);
                self.button.backgroundColor = UIColor.blueColor;
                [self.button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
                
                [self.view addSubview:self.button];
                [self.view addSubview:self.label];
                
            }
            - (void) press {
                secondViewController* second = [[secondViewController alloc] init];
                second.modalPresentationStyle = UIModalPresentationFullScreen;
                [second addObserver:self forKeyPath:@"context" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
                
                [self presentViewController:second animated:YES completion:nil];
            }
            - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
                if ([keyPath isEqual:@"context"]) {
                    id value = [change objectForKey:@"new"];
                    self.label.text = value;
                    
                }
            }
            
            - (void)viewDidLoad {
                [super viewDidLoad];
                // Do any additional setup after loading the view.
                
                self.view.backgroundColor = [UIColor orangeColor];
                self.backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
                self.backButton.frame = CGRectMake(100, 100, 100, 100);
                self.backButton.backgroundColor = [UIColor blueColor];
                [self.backButton addTarget:self action:@selector(pressBack) forControlEvents:UIControlEventTouchUpInside];
                [self.view addSubview:self.backButton];
                
                self.textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 250, 200, 50)];
                self.textField.keyboardType = UIKeyboardTypeDefault;
                self.textField.borderStyle = UITextBorderStyleRoundedRect;
                [self.view addSubview:self.textField];
                
            }
            - (void) pressBack {
                self.context = self.textField.text;
                [self dismissViewControllerAnimated:YES completion:nil];
            }
            

            运行的结果如下:

            刚进入的页面:

            iOS —— 初识KVO

            然后通过按钮进入到下一个界面。

            在textFiled中写入文本,

            iOS —— 初识KVO

            然后返回到前一个界面,之后会发现上一个界面中的值传到了这个界面中,如下图:

            iOS —— 初识KVO

            禁止KVO的方法

            //返回NO禁止KVO
            + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
                if ([key isEqualToString:@"content"]) {
                    return NO;
                } else {
                    return [super automaticallyNotifiesObserversForKey:key];
                }
            }
            

            注意事项:

            • 调用[removeObserver:forKeyPath:]需要在观察者消失之前,否则会导致Crash。
            • 在调用addObserver方法后,KVO并不会对观察者进行强引用,所以需要注意观察者的生命周期,否则会导致观察者被释放带来的Crash。
            • 观察者需要实现observeValueForKeyPath:ofObject:change:context:方法,当KVO事件到来时会调用这个方法,如果没有实现会导致Crash。
            • KVO的addObserver和removeObserver需要是成对的,如果重复remove则会导致NSRangeException类型的Crash,如果忘记remove则会在观察者释放后再次接收到KVO回调时Crash。
            • 在调用KVO时需要传入一个keyPath,由于keyPath是字符串的形式,所以其对应的属性发生改变后,字符串没有改变容易导致Crash。我们可以利用系统的反射机制将keyPath反射出来,这样编译器可以在@selector()中进行合法性检查。

免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]