【iOS】多界面传值

news2024/11/27 11:52:22

文章目录

  • 前言
  • 一、属性传值
  • 二、协议传值
  • 三、block传值
  • 四、KVO传值
  • 五、KVO的自动触发与手动触发
  • 六、通知传值
  • 总结


前言

在写网易云音乐以及3GShare包括后面的学生管理系统时,用到许多界面传值方法,特撰写博客记录目前学过的几种多界面传值方法

一、属性传值

属性传值是通过定义属性并设置值来实现传递数据的方式,多用于前一个页面向后一个页面传值
假设有两个视图控制器:ViewControllerA 和 ViewControllerB。

在 ViewControllerA.h 文件中定义一个属性:

#import <UIKit/UIKit.h>

@interface ViewControllerA : UIViewController

@property (nonatomic, strong) NSString *dataToPass;

@end

在 ViewControllerA.m 文件中设置一个按钮点击事件,当点击按钮时,跳转到 ViewControllerB 并传递数据:

#import "ViewControllerA.h"
#import "ViewControllerB.h"

@implementation ViewControllerA

- (void)buttonTapped {
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] init];
    viewControllerB.receivedData = self.dataToPass;
    [self.navigationController pushViewController:viewControllerB animated:YES];
}

@end

在 ViewControllerB.h 文件中定义一个属性来接收从 ViewControllerA 传递过来的数据:

#import <UIKit/UIKit.h>

@interface ViewControllerB : UIViewController

@property (nonatomic, strong) NSString *receivedData;

@end

在 ViewControllerB.m 文件中可以使用接收到的数据进行相应的操作:

> #import "ViewControllerB.h"
> 
> @implementation ViewControllerB
> 
> - (void)viewDidLoad {
>     [super viewDidLoad];
>     
>     // 使用接收到的数据
>     NSLog(@"Received data: %@", self.receivedData); }
> 
> @end

这样,当在 ViewControllerA 视图控制器中点击按钮,切换到 ViewControllerB 视图控制器时,就可以将 dataToPass 的值传递给 receivedData,并在 ViewControllerB 中使用接收到的数据。


二、协议传值

协议传值是通过定义协议和代理方法,在不同的视图控制器之间传递数据的方式。多用于后一个页面将数据回传给前一个页面

这里以3GShare注册界面回传账号密码给登录界面的协议传值作为示例并讲解其步骤:

  1. 定义协议:
    在发送数据的视图控制器(通常是源视图控制器)的头文件中定义一个协议,其中包含需要传递的数据的代理方法
    在这里插入图片描述
    这步需要我们定义协议的名称后再去定义回传数据的方法

  2. 声明代理属性:
    在发送数据的视图控制器的头文件中声明一个代理属性,用于保存代理对象。
    在这里插入图片描述

  3. 触发代理方法:
    在发送数据的视图控制器中,在适当的时机,触发代理方法,并将需要传递的数据作为参数传递给代理方法。
    在这里插入图片描述

  4. 实现代理方法:
    接收数据的视图控制器,也就是前一个控制器(通常是目标视图控制器)中,遵循协议并实现代理方法,以接收传递过来的数据。
    在这里插入图片描述

  5. 设置代理:(这是最重要的一步,很多人会忘了这步)
    在发送数据的视图控制器中,在跳转到接收数据的视图控制器之前,设置目标视图控制器的代理为当前视图控制器。
    在这里插入图片描述
    通俗的理解就是将后面的视图控制器的代理对象设为前一个视图控制器,让后一个为前一个代理,也就是手下替老板做事,然后将结果告诉老板


三、block传值

block传值同样也用于后面向前面传值,与协议传值有些相似的地方,但它使用代码块进行传值

  1. 定义 Block:
    在发送方(当前视图控制器)中定义一个 Block 属性,用于接收传递的数据。Block 的类型取决于你要传递的数据类型。
typedef void(^testblock)(NSString *);
@property(nonatomic, copy)testblock send;

typedef: 这是一个关键字,用于定义一个数据类型的别名,将后面的复杂类型定义简化为一个简洁的名字。
void(^testblock): 这部分是 Block 的类型定义,其中 testblock 是这个 Block 的别名,也就是我们定义的数据类型名。
(NSString *): 这是 Block 的参数列表,用括号括起来,表示 Block 接受一个 NSString 类型的参数。

这里需要注意的是:

typedef void(^testblock)(NSString *);:这是一个 Block 类型的定义,其中 testblock 是我们给这个 Block 类型起的别名,类似于自定义的数据类型。这个 Block 接受一个 NSString 类型的参数,并且没有返回值。

  1. 发送方设置 Block:
    在发送方视图控制器中设置 Block,将需要传递的数据作为 Block 的参数传入,并执行 Block。
    在这里插入图片描述
    在这段代码中,我将self.textField.text作为参数传入我的代码块,前一个视图控制器接收到的信息就是我传进去的参数
  2. 接收数据:
    在需要接受的地方将传回来的值进行使用,这里的(NSString *sendtext)中的sendtext就是回传回来的值
    在这里插入图片描述

这里给出block传值的实现动画
在这里插入图片描述


四、KVO传值

KVO(Key-Value Observing)是一种iOS编程中的一种观察者模式,用于监听对象属性值的变化。通过KVO,一个对象可以监视另一个对象的属性,当被监视的属性值发生变化时,会收到通知并执行相应的操作。

KVO实现步骤:

  1. 注册观察者:

在需要监听属性变化的对象(被观察者)中,调用addObserver:forKeyPath:options:context:
方法来注册观察者。这个方法告诉系统哪个对象要观察哪个属性,以及观察的选项和上下文。

假设我们有一个 Person 类,其中有一个属性 age,我们希望在另一个视图控制器中监听 age 的变化。

	self.person = [[Person alloc] init];
    self.person.age = 3;
    
    // 注册观察者
    [self.person addObserver:self
                  forKeyPath:@"age"
                     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                     context:NULL];

observer: 这是观察者对象,即要接收属性变化通知的对象。通常是当前视图控制器或其他感兴趣的对象。
keyPath: 要监听的属性的名称,以字符串表示。当该属性的值发生变化时,KVO 就会通知观察者。
options: 一个枚举值,用于指定监听的选项。这个参数可以设置为多个选项的组合,使用按位或(|)进行连接。常见的选项有:
NSKeyValueObservingOptionNew: 当属性的值发生变化时,提供新的属性值作为通知的参数。
NSKeyValueObservingOptionOld: 当属性的值发生变化时,提供旧的属性值作为通知的参数。
NSKeyValueObservingOptionInitial: 在添加观察者时,立即发送一次通知,提供当前属性的值作为通知的参数。
NSKeyValueObservingOptionPrior: 在属性值发生实际变化之前,先发送一次通知,提供旧的属性值作为通知的参数。
context: 这是一个指针类型的参数,用于传递额外的上下文信息。通常情况下可以传入 NULL,表示不需要传递上下文信息。如果你需要在观察者中处理一些额外的信息,可以使用自定义的指针类型来传递数据。

  1. 实现监听方法:
    在观察者对象中,实现一个监听方法- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context,监听方法会在被观察的属性发生变化时被调用。
// 实现监听方法,当 age 属性变化时会调用该方法
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"age"]) {
        // 获取旧值和新值
        NSNumber *oldAge = [change valueForKey:NSKeyValueChangeOldKey];
        NSNumber *newAge = [change valueForKey:NSKeyValueChangeNewKey];
        NSLog(@"old age: %@ --- new age: %@", oldAge, newAge);
    }
}

我们常用[change valueForKey:NSKeyValueChangeOldKey][change valueForKey:NSKeyValueChangeNewKey]来获得我们的新值与旧值

  1. 移除观察者:
    在观察者对象不再需要监听属性变化时,记得调用 removeObserver:forKeyPath: 方法来移除观察者,避免潜在的内存泄漏。
    在这里插入图片描述
    实现效果
    在这里插入图片描述在这里插入图片描述

五、KVO的自动触发与手动触发

一般来说,我们使用KVO来监听对象的属性,都是针对对象的单个属性,但如果我们想监听一个集合,上面的方法就不适用了。这是因为KVO的触发类型分为自动与手动,我们上面讲述的仅仅只是KVO的自动触发

  • 自动触发KVO通常适用于以下情况:

监听对象属性的变化:对于简单的对象属性,例如字符串、数字等,可以使用自动触发KVO。就像我们上面设置了一个age,这就是简单的对象属性,只需要在被监听属性声明前加上@property关键字,并使用nonatomic修饰符即可。当属性值发生变化时,KVO会自动发送通知给观察者。
使用@synthesize合成属性:在使用@synthesize合成属性时,如果指定了观察者,则合成的属性会自动触发KVO通知。

  • 手动触发KVO通常适用于以下情况:

监听集合属性的变化:集合属性不支持自动触发KVO通知,所以需要使用手动触发KVO来监听集合属性的变化。在修改集合属性之前调用willChangeValueForKey:方法,在修改完成后调用didChangeValueForKey:方法。
监听非对象类型属性:对于非对象类型的属性,例如C语言基本数据类型,由于它们不是对象,无法自动触发KVO。这时需要使用手动触发KVO通知来监听属性的变化。
自定义KVO通知:有时候我们可能需要在一些特定的场景下自定义KVO通知,这时可以使用手动触发KVO来实现。


这样一来我们知道了如果对象的设置的属性是集合的话,我们需要手动来触发我们的KVO,接下来讲一下原因:

当我们监听一个集合属性时(如NSMutableArray类型属性),KVO默认只会监听这个集合属性的变化,但不会监听集合中的元素的变化。也就是说,如果我们直接修改集合中的元素(比如使用addObject:方法),而没有通过集合属性的setter方法进行修改,KVO是无法察觉到集合中元素的变化的。

通俗的讲,我们的KVO的自动触发只适用于用setter方法修改的属性,也就是用点语法修改的属性都会自动触发我们的KVO,但是集合无法用点语法进行修改,那么这个时候就需要用到我们的手动触发


为了解决这个问题,我们需要在修改集合属性之前,调用willChangeValueForKey:方法,在修改之后,调用didChangeValueForKey:方法。这样做可以手动触发KVO通知,告诉KVO机制集合属性发生了变化,使得KVO能够正确地监听到集合中元素的变化。

  • 我们在原来的对象中添加一个集合属性
    在这里插入图片描述
  • 我们将简单的对象属性添加到我们的集合中,同时将我们的监听对象改为我们的集合
    在这里插入图片描述在这里插入图片描述
    此时我还没有去手动触发我们的KVO,我们试着运行一下程序:
    在这里插入图片描述
    我们的内容并没有变化,这也说明了我们并没有触发我们的KVO的监听方法
  • 接下来我们将实现手动监听
    在这里插入图片描述

willChangeValueForKey::在对象属性发生变化之前调用,用于通知KVO即将开始监听属性的变化。
didChangeValueForKey::在对象属性发生变化后调用,用于通知KVO属性的变化已经完成。
willChangeValueForKey 和 didChangeValueForKey 方法通过配对,这样可以通知观察者(监听者)该属性值即将发生变化和已经发生变化。这对于手动触发 KVO 监听非常重要,需要注意的是,这两种方法一定是配对出现的
在这里插入图片描述在这里插入图片描述

自此,我们实现了我们KVO对集合类型的监听


六、通知传值

通知传值是一种在不同对象之间进行信息传递的方式,它使用了通知中心来实现观察者模式,允许一个对象在发生改变时通知其他观察者对象。其可以用于跨多个界面传值

其步骤简单分为四步

  1. 创建并发送通知:
    首先,在发送者对象中创建一个通知,并指定通知的名称(通常使用字符串来表示)。可以通过NSNotification类或NSNotificationName宏来创建通知。需要传递信息给其他对象时,可以通过NSNotificationCenter的postNotificationName:object:userInfo:方法来发送通知。在发送通知时,可以附带一些额外的信息(如字典)作为通知的userInfo参数。
    在这里插入图片描述
    我们接下来详细看一下创建与发送通知的方法:
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

aName: 通知的名称,是一个字符串类型的参数。通过这个名称来标识不同的通知。发送通知时,需要指定要发送的通知的名称,接收通知时,也需要监听相应名称的通知。
anObject: 通知的发送者,是一个可选参数。通知可以有一个发送者,表示是哪个对象发送了这个通知。通常情况下,我们不需要传递发送者,可以传入nil。
aUserInfo: 通知的附加信息,是一个可选参数。可以通过这个字典传递一些额外的信息给接收通知的对象。通常情况下,我们在发送通知时,可以将一些需要传递的数据放入这个字典中。

这里需要注意的是我们的userInfo:后跟的参数是一个字典类型,我们通过传回一个字典,并通过查找字典的key来获取我们需要的数据

  1. 注册观察者:
    在接收者对象中,需要注册对某个通知感兴趣的观察者。这样,当通知被发送时,观察者就能接收到通知并做出相应的响应。使用NSNotificationCenter的addObserver:selector:name:object:方法来注册观察者。
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;

observer: 要注册的观察者对象。观察者对象将接收到与指定通知名称匹配的通知。通常,这个参数是当前对象,即要接收通知的对象。
selector: 观察者对象中用于处理通知的方法(函数)的选择器。这个方法必须带有一个参数,通常是 NSNotification 对象,用于接收传递的通知信息。该方法的声明通常形如 -(void)methodName:(NSNotification *)notification;。
name: 要观察的通知名称。这是一个字符串,用于标识要监听的通知。当发送通知时,只有与这个名称匹配的通知才会被发送给观察者。
object: 通知发送者的对象。如果设置为 nil,则会接收任何发送给指定名称的通知。如果设置为特定对象,只有该对象发送的与指定名称匹配的通知才会被发送给观察者。

这里有一点需要特别注意的就是要观察的通知名称必须于创造的通知的名称相同,否则无法接受来自通知的数据
在这里插入图片描述

  1. 接收通知:
    接收者对象需要实现一个方法,用于处理接收到的通知。这个方法是在观察者注册时通过selector参数指定的。当通知被发送时,通知中心会调用这个方法,并传递相关的信息给观察者。
    以我们上面的方法为例,receiveNotice:就是我们处理通知的方法
    在这里插入图片描述

  2. 移除观察者:
    在接收者对象被销毁之前,需要将其从通知中心中移除,避免出现潜在的内存泄漏。可以使用NSNotificationCenter的removeObserver:系列方法来移除观察者。

- (void)dealloc {
    // 移除通知观察者
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

接下来让我们看一下效果:
在这里插入图片描述
这样一来,我们就实现了通知传值

总结

多界面传值是iOS中十分重要的知识,笔者还有很多知识还没学到例如KVC等,以后学到了会加以补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/781817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zabbix-server监控mysql及httpd服务

目录 一、Zabbix监控mysql数据库 1、为server.Zabbix.com添加服务模板 2、创建mysql服务图形 二、server.zabbix.com服务器操作 编辑chk_mysql.sh脚本 三、server.Zabbix.com测试 四、查看web效果 五、Zabbix监控apache&#xff08;httpd服务&#xff09; 安装master 六、…

基于Python+多层RNN+Tensorflow藏头诗与歌词智能生成-深度学习算法应用(含全部工程源码)+训练数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Tensorflow 环境PyCharm环境 模块实现古诗生成1. 数据预处理2. 模型构建3. 模型训练及保存4. 使用模型生成古诗5. 产生藏头诗6. 用词云展示生成的古诗 歌词生成1. 数据预处理2. 模型构建3. 模型训练并保存4. 生成…

时序约束案例(没有解决)

问题记录 SDI显示项目要求:当外部摄像头无接入时&#xff0c;FPGA产生彩条给显示芯片。当外部摄像头有接入时&#xff0c;显示数据来自于海思。目前能成功显示&#xff0c;但是需要把输出给显示驱动芯片的时钟取反后才可以。尝试使用output delay约束不成功。 项目架构描述 …

【Redis-02】Redis的缓存

Redis的缓存 1.概念1.1什么是缓存1.2为什么使用缓存1.3如何使用1.3.1不适用缓存之前1.3.2 缓存模型和思路&#xff08;使用方法&#xff09;1.3.3 使用之后 2.缓存更新策略2.1数据库缓存不一致解决方案2.2数据库和缓存不一致采用什么方案2.3代码实例 3.缓存穿透3.1缓存穿透是什…

Qt6 Qt Quick UI原型学习QML第六篇

文章目录 效果展示动画片第一小节源码&#xff08;AnimationExample.qml&#xff09;主文件解释语法 源码子文件&#xff08;ClickableImageV2.qml&#xff09;解释语法 效果展示 动画片第一小节 源码&#xff08;AnimationExample.qml&#xff09;主文件 import QtQuick 2.1…

自动驾驶感知系统-激光雷达

感知系统 现有的车载传感器主要包括超声波雷达、激光雷达、毫米波雷达、车载摄像头、红外探头等。主流的自动驾驶感知平台以雷达和车载摄像头为主&#xff0c;呈现多传感器融合发展趋势。基于测量能力和环境适应性&#xff0c;预计雷达和车载摄像头会保持其感知平台霸主地位&a…

Python Selenium设计模式及代码实现

前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享&#xff0c;以便大家在实践中对POM的特点、应用场景和核心思想有一定的理解和掌握。 为什么要用POM 基于python selenium2开始UI级自动化测试并不是多么艰巨的任务。**只需要定位到元素&#xff0c;…

vue中export和export default的使用

<script> export default {name: HelloWorld } $(function () {alert(引入成功) }) </script> 1、export的使用 比喻index.js要使用test.js中的数据&#xff0c;首先在test.js文件中进行导出操作 代码如下&#xff1a; export function list() {alert("list…

EasyExcel写出包含多个sheet页的Excel

EasyExcel导出包含多个sheet页的Excel 1.引入依赖 引入如下的EasyExcel的依赖&#xff0c;或直接下载jar包 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></depende…

文心千帆大模型平台,一站式企业级大模型平台

文心千帆大模型平台&#xff0c;一站式企业级大模型平台 0. 前言1. 人工智能发展历程1.1 传统机器学习1.2 深度学习1.3 大模型时代 2. 文心千帆2.1 文心千帆介绍2.2 文心千帆应用场景2.3 文心千帆平台优势 3. 文心千帆初体验3.1 注册流程3.2 创建应用3.3 在线测试3.4 数据服务3…

玩转ChatGPT:Custom instructions (vol. 1)

一、写在前面 据说GPT-4又被削了&#xff0c;前几天让TA改代码&#xff0c;来来回回好几次才成功。 可以看到之前3小时25条的限制&#xff0c;现在改成了3小时50条&#xff0c;可不可以理解为&#xff1a;以前一个指令能完成的任务&#xff0c;现在得两条指令&#xff1f; 可…

如何将windows下的应用程序直接放到ubuntu下运行

安装wine https://blog.csdn.net/gc_2299/article/details/129077372 安装.NET https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472

Vue中的props配置

结构&#xff1a; main.js //引入Vue import Vue from vue //引入App import App from "./App"; //关闭Vue的生产提示 Vue.config.productionTip false//创建vm new Vue({el:#app,render:h>h(App) }) App.vue <template><div><Student name&qu…

运行Yolov5 7.0遇到的问题

遇到的错误 Traceback (most recent call last):File "E:\Users\user\anaconda3\envs\torch17\lib\site-packages\git\__init__.py", line 89, in <module>refresh()File "E:\Users\user\anaconda3\envs\torch17\lib\site-packages\git\__init__.py"…

RocketMQ Windows环境下启动导致C盘爆满原因及解决办法

原因 rocketmq取的默认路径是user.home路径&#xff0c;也就是用户的根目录&#xff0c;一般存储放在跟路径下的 /store目录。 在源码中也可以看到&#xff1a; 这里会有一个问题&#xff0c;RocketMQ很容易导致C盘空间不够&#xff0c;在使用过程中&#xff0c;创建一个主题默…

二,jmeter的简介和使用

文章目录 一、jmeter简介及安装1. 简介2. 安装 二、jmeter设置语言三、jmeter文件路径说明四、编写jmeter脚本五、乱码的处理&#xff1a;1. 请求内容出现乱码处理方法2. 响应内容出现乱码处理方法 六、写脚本方法扩展录制脚本&#xff1a; 七、 脚本功能增强 一、jmeter简介及…

pytorch学习——第二个模型(逻辑回归)

参考该博客系统学习Pytorch笔记二&#xff1a;Pytorch的动态图、自动求导及逻辑回归 c l a s s { 0 0.5 > y 1 0.5 ≤ y class\left\{ \begin{array}{rcl} 0 & & {0.5 > y}\\ 1 & & {0.5 \le y}\\ \end{array} \right. class{01​​0.5>y0.5≤y​ 根…

图数据库Neo4j学习一——基本介绍

文章目录 1各类数据库基本概念1.1关系型数据库&#xff08;SQL&#xff09;1.2非关系型数据库&#xff08;NoSQL&#xff09;1.3图数据库1.3.1图数据库特点1.3.2图数据库应用场景 2图数据库基本概念2.1用户访问菜单2.2节点&#xff08;用户、角色、菜单&#xff09;2.3关系&…

动态规划:从入门到入土系列(一)

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 前言 本篇…

高级web前端开发工程师岗位的具体内容概述

高级web前端开发工程师岗位的具体内容概述1 职责&#xff1a; 1、负责前端页面开发和维护&#xff0c;并根据需求优化产品性能、用户体验、交互效果及各种主流浏览器以及各类型移动客户端的兼容适配工作; 2、配合产品经理和UI设计师&#xff0c;通过各种前端技术手段&#xf…