iOS —— 初识KVO
iOS —— 初始KVO
- KVO的基础
- 1. KVO概念
- 2. KVO使用步骤
- 注册KVO监听
- 实现KVO监听
- 销毁KVO监听
- 3. KVO基本用法
- 4. KVO传值
- 禁止KVO的方法
- 注意事项:
KVO的基础
1. KVO概念
KVO是一种开发模式,它的全称是Key-Value Observing (观察者模式) 是苹果Fundation框架下提供的一种开发机制,使用KVO,可以方便地对指定对象的某个属性进行观察,当属性发生变化时,进行通知,告诉开发者属性旧值和新值对应的内容。
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<NSKeyValueChangeKey,id> *)change context:(void *)context {//打印监听结果if ([keyPath isEqual:@"backgroundColor"]) {NSLog(@"old value is: %@", [change objectForKey:@"old"]);NSLog(@"new value is: %@", [change objectForKey:@"new"]);}
}
我们点击一次button:

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<NSKeyValueChangeKey,id> *)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];
}
运行的结果如下:
刚进入的页面:

然后通过按钮进入到下一个界面。
在textFiled中写入文本,

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

禁止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()中进行合法性检查。
相关文章:
iOS —— 初识KVO
iOS —— 初始KVO KVO的基础1. KVO概念2. KVO使用步骤注册KVO监听实现KVO监听销毁KVO监听 3. KVO基本用法4. KVO传值禁止KVO的方法 注意事项: KVO的基础 1. KVO概念 KVO是一种开发模式,它的全称是Key-Value Observing (观察者模式) 是苹果Fundation框架…...
什么是HTTP? HTTP 和 HTTPS 的区别?
文章目录 一、HTTP二、HTTPS三、区别参考文献 一、HTTP HTTP (HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范 在计算机和网络世界有,存在不同的协议,如广播协议、寻址协议、路由协议等等… 而HTTP是…...
微信小程序如何进行npm导入组件
文章目录 目录 文章目录 前言 一、安装node 二、微信小程序通过npm安装组件(以Vant-weapp为例) 一、Vant-weapp下载 二 、修改 app.json 三 、修改 project.config.json 四 、 构建 npm 包 前言 微信小程序使用npm导入有很多的教程,我…...
MySQL编程实战LeetCode经典考题
文章简介 本文主要收集了LeetCode上关于MySQL的一些经典考题。 后续也会陆续把所有经典考题补充完整。 175.组合两个表 175.组合两个表 解答: select p.FirstName as firstName, p.LastName as lastName,a.City as city, a.State as state from Person p l…...
发生播放错误,即将重试 jellyfin
上周在家里的小主机上部署了jellyfin,真香,手机安卓端使用无问题,于是今天准备在电视上安装一个 首先是直接安装的手机版客户端,操作卡顿,而且很多操作没法实现,于是去下了一个tv版本 安装上后发现&#…...
BIONIOAIO
通信技术整体解决的问题 1.局域网内的通信要求 2.多系统间的底层消息传递机制 3.高并发下,大数据量的通信场景需要 4.游戏行业。无论是手游服务端、还是大型网络游戏,java的应用越来越广 IO模型基本说明 就是用什么样的通道或者说是通信模式和架构…...
SpringSecurity学习总结(三更草堂)
SpringSecurity安全框架的核心功能是认证和授权: 认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户。 授权:经过认证后判断当前用户是否具有进行某个操作的权限。 一般来说中大型的项目都是使用SpringSecurit…...
C++20中的jthread
一、多线程开发 c11以前,是不包含线程库的,开发多线程,必须使用OS系统自带的线程API,这就导致了很多问题,最主要的是,跨平台的开发,一般要保持几个主流应用的库的代码支持,特别是对…...
Xception模型详解
简介 Xception的名称源自于"Extreme Inception",它是在Inception架构的基础上进行了扩展和改进。Inception架构是Google团队提出的一种经典的卷积神经网络架构,用于解决深度卷积神经网络中的计算和参数增长问题。 与Inception不同࿰…...
【合合TextIn】AI构建新质生产力,合合信息Embedding模型助力专业知识应用
目录 一、合合信息acge模型获MTEB中文榜单第一 二、MTEB与C-MTEB 三、Embedding模型的意义 四、合合信息acge模型 (一)acge模型特点 (二)acge模型功能 (三)acge模型优势 五、公司介绍 一、合合信息…...
Flutter 拦截系统键盘,显示自定义键盘
一、这里记录下在开发过程中,下单的时候输入金额需要使用自定义的数字键盘 参考链接: https://juejin.cn/post/7166046328609308685 效果图 二、屏蔽系统键盘 怎样才能够在输入框获取焦点的时候,不让系统键盘弹出呢?同时又显示我们自定义的…...
内存泄漏是什么?如何避免内存泄漏?
1.2 内存泄漏 使用new开辟空间泄漏,抛出异常 int main() {int size 0;try{while (1){//int* p (int*)malloc(sizeof(int) * 1024 * 1024);/*if (p NULL){break;}*/int* p new int[1024 * 1024];size size 4 * 1024 * 1024;cout << p << endl;}}…...
linux 中的syslog的含义和用法
在Linux系统中,syslog是一种系统日志服务,用于收集、存储和管理系统和应用程序生成的日志消息。syslog服务负责记录系统的运行状态、错误信息、警告、调试信息等,以便系统管理员可以监控系统的健康状况、故障排查和性能优化。 含义和作用&am…...
kubernetes(K8S)学习(一):K8S集群搭建(1 master 2 worker)
K8S集群搭建(1 master 2 worker) 一、环境资源准备1.1、版本统一1.2、k8s环境系统要求1.3、准备三台Centos7虚拟机 二、集群搭建2.1、更新yum,并安装依赖包2.2、安装Docker2.3、设置hostname,修改hosts文件2.4、设置k8s的系统要求…...
巧克力(蓝桥杯)
文章目录 巧克力题目描述解题分析贪心 巧克力 题目描述 小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。 一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的…...
Python爬虫之pyquery和parsel的使用
三、pyquery的使用 1、准备工作 pip3 install pyquery2、初始化 2.1、字符串初始化 把HTML的内容当做参数,来初始化PyQuery对象。 html <div><ul><li class"item-0">first item</li><li class"item-1">&l…...
移动硬盘怎么加密?移动硬盘加密软件有哪些?
移动硬盘是我们在工作中最常用的移动存储设备,为了保护数据安全,需要使用专业的移动硬盘加密软件加密保护。那么,移动硬盘加密软件有哪些? BitLocker BitLocker是Windows的磁盘加锁功能,可以用于加密保护移动硬盘中…...
openEuler 22.03 安装 .NET 8.0
openEuler 22.03 安装 .NET 8.0 openEuler 22.03 安装 .NET 8.0 openEuler 22.03 安装 .NET 8.0 查看内核信息 [jeffPC-20240314EIAA ~]$ cat /proc/version Linux version 5.15.146.1-microsoft-standard-WSL2 (root65c757a075e2) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils)…...
【转载】OpenCV ECC图像对齐实现与代码演示(Python / C++源码)
发现一个有很多实践代码的git 库,特记录下: 地址:GitHub - luohenyueji/OpenCV-Practical-Exercise: OpenCV practical exercise 作者博客地址:https://blog.csdn.net/LuohenYJ 已关注。 Items项目Resources1age_gender1基于深度学习识别人脸性别和年龄Model2OpenCV_dlib_…...
每日一题(相交链表 )
欢迎大家来我们主页进行指导 LaNzikinh-CSDN博客 160. 相交链表 - 力扣(LeetCode) 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节…...
3大核心能力实现高效水印移除:WatermarkRemover-AI全解析
3大核心能力实现高效水印移除:WatermarkRemover-AI全解析 【免费下载链接】WatermarkRemover-AI AI-Powered Watermark Remover using Florence-2 and LaMA Models: A Python application leveraging state-of-the-art deep learning models to effectively remove …...
如何利用OpenCode实现高效专业的AI驱动开发工作流?
如何利用OpenCode实现高效专业的AI驱动开发工作流? 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手,模型灵活可选,可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode 在当今快速迭代的软件开发…...
从八股到实战!3月25日Python高并发面试,TaskGroup+JIT双杀通关
面试官推了推眼镜,盯着你的简历:“说说Python高并发吧,asyncio用过吗?” 你心里冷笑一声。这要是搁三年前,你肯定开始背诵:"asyncio是Python的异步IO库,使用事件循环机制,通过a…...
2026年(新锐)期刊分区表正式发布(附下载)
2026年3月24日,由新锐学术研制的《新锐期刊分区表》(简称“新锐分区”)正式推出。据中国科学院期刊分区表公众号2025年11月介绍:应广大用户的要求,"期刊分区表"公众号将专注于发布期刊分区表相关的动态信息&…...
DAMA数据资产目录实战:从零搭建企业级数据管理系统的5个关键步骤
DAMA数据资产目录实战:从零搭建企业级数据管理系统的5个关键步骤 当企业数据量呈指数级增长时,最令人头疼的往往不是存储问题,而是"数据在哪?谁能用?怎么用?"这三个灵魂拷问。去年我们为一家中型…...
扶梯安全开关硬件抽象库:轻量级嵌入式状态识别方案
1. 项目概述EscalatorSwitch 是一个面向自动扶梯安全控制场景的轻量级嵌入式硬件抽象库,其核心定位并非通用IO驱动,而是针对电梯/扶梯行业特有的“扶梯运行状态切换开关”(Escalator Switch)这一专用机电装置提供标准化、可复用的…...
Vue Toast组件:轻量级通知解决方案的无侵入式集成实践
Vue Toast组件:轻量级通知解决方案的无侵入式集成实践 【免费下载链接】vue-sonner 🔔 An opinionated toast component for Vue. 项目地址: https://gitcode.com/gh_mirrors/vu/vue-sonner 在现代Web应用开发中,用户交互反馈是提升体…...
CC1310开发者的福音:IAR for ARM 8.2到8.32版本迁移避坑指南
CC1310开发者的福音:IAR for ARM 8.2到8.32版本迁移避坑指南 对于使用CC1310开发板的嵌入式开发者来说,IAR for ARM无疑是最常用的开发工具之一。然而,当我们需要从8.2版本升级到8.32版本时,往往会遇到各种意想不到的兼容性问题。…...
如何使用 Flutter 开发 HarmonyOS 应用
文章目录为什么使用 Flutter 来开发?搭建 Flutter 开发环境mac 环境变量示例win 环境变量参考验证环境变量是否配置成功集成与调试 Flutter OH SDKFlutter 开发环境搭建第一个 Flutter OH 程序其它常用 Flutter OH 命令题外话Flutter OH 参考文档Author:…...
开源IT资产管理系统Snipe-IT:从混乱到有序的数字化转型之路
开源IT资产管理系统Snipe-IT:从混乱到有序的数字化转型之路 【免费下载链接】snipe-it A free open source IT asset/license management system 项目地址: https://gitcode.com/GitHub_Trending/sn/snipe-it 在企业数字化进程中,IT资产如同散落的…...
