当前位置: 首页 > news >正文

多界面传值

多界面传值

  • 前言
  • 属性传值
  • 协议传值
  • block传值
  • 通知传值
  • KVO传值
  • 总结

前言

在先前的的仿写中多次使用到了不同界面的传值,这里作一个总结。

属性传值

属性传值是最常用、最简单的一种控制器间数据传递方式,是通过定义属性并设置值来传递数据的。

以在3gshare关注状态的仿写的内容为例,将要跳转进的视图控制器定义为属性,在每次push时,判断该属性是否已经被初始化,如果没有,则初始化,否则不重复操作初始化,使得push进的界面的状态被保留,而不是反复刷新。

@property(nonatomic, strong) FollowViewController *followVC;
if (!self.followVC) {self.followVC = [[FollowViewController alloc] init];self.followVC.title = @"新关注的";self.followVC.followStatus = self.followStatus;
} else {self.followVC.followStatus = self.followStatus;
}
[self.navigationController pushViewController:self.followVC animated:YES];
-(void)pressBtn:(UIButton*)button {NSInteger index = button.tag; BOOL selected = ![self.followStatus[index] boolValue];self.followStatus[index] = @(selected);button.selected = selected;
}

效果不再重复展示。

协议传值

协议传值是通过定义协议和代理方法的方式进行多界面传值,常用于反向传值,也就是从第二个页面把数据回传到第一个页面。实现方法是第二页定义一个协议,第一页遵守并实现协议方法,然后第二页通过代理对象调用协议方法,把数据回去。

这里我们依然以3gshare的仿写中注册界面将账号信息传回给登录界面为例:

  • 定义协议和声明代理属性(一般定义在被传值的界面,也就是发送数据的一方
@protocol InformationDelegate <NSObject>-(void)setupInformation:(NSMutableDictionary*)dictionary;@end@interface RegisterViewControl : UIViewController@property(nonatomic, weak) id<InformationDelegate> dictDelegate;@end
  • 触发代理方法:也就是调用代理方法,一般在被传值的界面。
NSString *UserName = self.UserNameText.text;
NSString *PassWord = self.PassWordText.text;
NSDictionary *dict = [NSDictionary dictionaryWithObject:PassWord forKey:UserName];
[self.dictionary addEntriesFromDictionary:dict];
//self.dictionary交给代理对象self.dictDelegate执行方法setupInformation
[self.dictDelegate setupInformation:self.dictionary];
[self.navigationController popViewControllerAnimated:YES];
  • 实现代理方法(一般在传值的界面):也就是谁想接受传值的数据,就实现这个方法。
#import "LoginViewControl.h"
#import "RegisterViewControl.h"@interface LoginViewControl ()<UITextFieldDelegate, UITabBarDelegate, InformationDelegate>@end@implementation LoginViewControl-(void)setupInformation:(NSMutableDictionary*)dictionary {[self.dict addEntriesFromDictionary:dictionary];
}
  • 设置代理:这一步最重要也最容易被漏掉,它一般写在传值方,也就是接受数据的页面。
-(void)pressRegister {RegisterViewControl *registerVC = [[RegisterViewControl alloc] init];registerVC.dictDelegate = self;[self.navigationController pushViewController:registerVC animated:YES];
}

具体的效果展示也不再重复。

block传值

block传值跟协议代理传值的思路相似,也用于后面向前面的传值,但它使用代码块进行传值。

  • 定义block类型和属性
#import <UIKit/UIKit.h>typedef void(^SendBlock)(NSString *text);@interface BViewController : UIViewController@property(nonatomic, copy) SendBlock send;@end

typedef void(^SendBlock)(NSString *text)

  • typedof:定义类型别名
  • void(^SendBlock)(NSString *text):无返回值,带NSString参数的block类型
  • SendBlock:block名字

这里值得注意的是:属性为什么要用 copy

  1. 首先我们要知道block的存储位置,block 本质上是一个带有上下文的函数对象。根据创建场景不同,block 的存储位置不同:
  • 栈上:默认block分配在栈上,随着作用域结束就会被销毁。
  • 堆上:如果使用copy关键字,那么系统会将block从栈复制到堆上,这样即使超出作用域,block仍然继续存在。
  • 全局区:不捕获外部变量的 block,也叫全局 block,会直接存放在全局区,不需要 copy 就能安全使用。
  1. 然后我们再来考虑为什么属性要用copy而不是strong。
  • strong:赋值时,block可能还是栈上的block,当方法调用完后,栈内存释放,block也随之销毁,但strong修饰的属性还会持有一个悬空指针,访问就会崩溃。
  • copy:copy会把 block 拷贝到堆上,生命周期就不依赖原作用域,直到对象释放才销毁,是安全的。

这里我们再用一个代码来看一下区别:

#import <Foundation/Foundation.h>typedef void(^TestBlock)(void);@interface MyClass : NSObject@property(nonatomic, strong) TestBlock strongBlock;
@property(nonatomic, copy) TestBlock copyBlock;@end#import <Foundation/Foundation.h>
#import "MyClass.h"void test(void) {MyClass *obj = [[MyClass alloc] init];int value = 42;obj.strongBlock = ^{NSLog(@"strongBlock: %d", value);};obj.copyBlock = ^{NSLog(@"copyBlock: %d", value);};NSLog(@"strongBlock class: %@", [obj.strongBlock class]);NSLog(@"copyBlock class: %@", [obj.copyBlock class]);
}int main(int argc, const char * argv[]) {@autoreleasepool {test();}return 0;
}

运行结果:

在这里插入图片描述

我们发现运行结果和我们预想的不一样,无论strong还是copy,block都在堆上。我查阅了一下资料,发现这是编译器ARC模式下,系统自动帮我们做了一次copy操作,因此我们会发现block存储位置是一样的。然而在MRC模式下的输出结果是我们预想的那样。

这里有些超出我现学的知识,后续了解学习后来完善补充这里的内容。

  • 触发block:将要回传的数据作为block的参数传入并执行block。
- (void)backAndSend {if (self.send) {self.send(self.textField.text);}[self dismissViewControllerAnimated:YES completion:nil];
}

将输入框输入的内容作为参数传入block时,前一个视图控制器接收的信息就会是我传进去的参数。

  • 接收数据:在需要接受的地方将传回的值进行使用。
- (void)goToB {BViewController *bVC = [[BViewController alloc] init];bVC.send = ^(NSString *text) {self.label.text = [NSString stringWithFormat:@"收到: %@", text];};[self presentViewController:bVC animated:YES completion:nil];
}

展示一下效果:

在这里插入图片描述

通知传值

通知传值是一种适合一对多传值的传值方式,它使用了通知中心来实现观察者模式,允许一个对象在发生改变时通知其他观察者对象。

首先我们确定我们的目的,从A跳转到B,并且点击B中按钮将我们字典中存入的内容返回给A,也就是在B界面修改并传值给A界面。

  • 发送通知:

将B界面的值传回给A界面,因此在B界面发送通知。

[[NSNotificationCenter defaultCenter] postNotificationName:@"MyNotification"object:niluserInfo:info];
  • postNotificationName:通知的名称,通过该名称区分不同的通知,以便接收时,监视相应名称的通知。
  • object:通知的发送者,表示是哪个对象发送了这个通知。通常情况下,我们不需要传递发送者,可以传入nil。
  • userInfo:通知的附加信息,可以通过字典传递一些额外的信息给接收通知的对象。通常情况下,我们在发送通知时,将一些需要传递的数据放入这个字典中。
  • 注册监听,注册观察者:

B界面将值传回给A界面,因此在A界面注册监听,也就是A界面愿意接受B界面传回的值。

[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(receiveNotice:)name:@"MyNotification"object:nil];
  • addObserver:要注册的观察者对象,通常当前对象作为参数接受通知。
  • selector:观察者对象用于处理通知的方法,这个方法必须带有一个参数,通常是 NSNotification 对象,用于接收传递的通知信息。
  • name:要观察的通知名称,与通知名称匹配。
  • object:通知发送者的对象。如果设置为 nil,则会接收任何发送给指定名称的通知。如果设置为特定对象,只有该对象发送的与指定名称匹配的通知才会被发送给观察者。
  • 接收通知:

在A界面接收到传回来的值,也就是这个字典,并修改label

- (void)receiveNotice:(NSNotification *)notification {NSDictionary *info = notification.userInfo;NSString *msg = info[@"message"];self.label.text = msg;
}
  • 移除通知:

最重要且容易遗漏的一步,整个通知传值结束后,一定要移除通知,避免内存泄露

- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];
}

效果展示:

在这里插入图片描述

KVO传值

笔者此时还没有学习这种学习方式,今后学习后会来补充完善这里的内容。

总结

在仿写项目的过程中,多界面传值是很重要的部分,笔者会在学习后继续补充完善。


文章转载自:

http://pCsJmLGC.hLshn.cn
http://c0KBQErg.hLshn.cn
http://V3zq8Tif.hLshn.cn
http://UNSZHG7l.hLshn.cn
http://BCaZwN5J.hLshn.cn
http://kajLywGP.hLshn.cn
http://oO6eNusG.hLshn.cn
http://LRRzmbhP.hLshn.cn
http://ZMVPvf20.hLshn.cn
http://GtlnYZLM.hLshn.cn
http://5eC3m20p.hLshn.cn
http://BebIgkNA.hLshn.cn
http://NttJlPVO.hLshn.cn
http://GSBwtGnV.hLshn.cn
http://2j5yJbpv.hLshn.cn
http://du8oyvyH.hLshn.cn
http://MqEsFzop.hLshn.cn
http://T4AjxEtH.hLshn.cn
http://RJYpMA3o.hLshn.cn
http://Y2Qc1VTH.hLshn.cn
http://1XProUxS.hLshn.cn
http://irXqz6Y5.hLshn.cn
http://MfrtDjXD.hLshn.cn
http://6gsYfar4.hLshn.cn
http://xQQhdQY8.hLshn.cn
http://L7Tg3Jrw.hLshn.cn
http://rCsmihRp.hLshn.cn
http://Q0MoOufn.hLshn.cn
http://0EKcKabo.hLshn.cn
http://Xnd1xxS6.hLshn.cn
http://www.dtcms.com/a/371966.html

相关文章:

  • shell编程-案例
  • Docker--宿主机和容器相互拷贝文件
  • 打包成 UMD,通过 CDN静态资源共享:微前端项目中跨项目共享公共组件的最佳实践
  • 关于物料采购合同,付款规则库的程序设计(刘欣)
  • 自然语言处理 基于神经网络的词向量转化模型word2vec
  • 【数据分析】一种用于校正微生物组数据中批次效应的多变量框架
  • Spring WebFlux响应式编程原理深度解析与性能优化实践指南
  • ZYNQ UART中断
  • SimLingo:纯视觉框架下的自动驾驶视觉 - 语言 - 动作融合模型
  • 计算机视觉(十):ROI
  • 【设计模式】UML类图关系中的数量表示(详细版)
  • 利用 SeBackupPrivilege 的最快方法
  • 华为基于IPD的产品质量计划模板
  • leecoede 二分查找 题集
  • 编写第一个程序-Ai8051U-32bit,Keil设置
  • Objective-C方法参数标签怎么设置
  • 国内外最新AI语言模型行情分析2025年9月最新内容
  • [数据结构] 栈和队列
  • 基于moduo库实现protobuf通信
  • Android开发-图像显示
  • OpenHarmony之设备风险管理平台(SecurityGuard)模块源码详解
  • Kotlin 协程之 Flow 的理解使用及源码解析
  • Vue2.x核心技术与实战(六)-Vuex
  • 认知篇#12:基于非深度学习方法的图像特征提取
  • 软考备考①
  • 信息安全工程师软考攻坚:第三章网络安全技术深度解析与实战训练
  • JDK17日期格式‘MMM’导致九月Sept/Sep格式化异常问题❗❗❗
  • Vulkan 学习(20)---- UniformBuffer 的使用
  • 微信小程序中实现AI对话、生成3D图像并使用xr-frame演示
  • 【不背八股】9.MySQL知识点汇总