iOS多界面传值
文章目录
属性传值
这个传值方式和他的名字一样,我们主要还是通过属性对值进行一个传递,主要应用场景是前一个页面向后一个页面传值。
首先我们先要设置一个属性
@interface secondViewController : UIViewController @property (nonatomic, assign) NSInteger tag; //tag就是我们设置的一个属性 @end
其次我们需要在某一个地方触发传值的事件,然后通过事件进行一个传递,这里我设置一个button来触发传值事件
-(void)press { secondViewController* second = [[secondViewController alloc] init]; second.tag = _num; [self.navigationController pushViewController:second animated:YES]; }
然后我们这新的页面就拿到了这个数值,可以对然后就可以对这个数值进行一个相应的处理了
- (void)viewDidLoad { ···· self.label.text = [NSString stringWithFormat:@"%ld", _tag]; NSLog(@"%ld", _tag); ···· // Do any additional setup after loading the view. }
属性传值比较简单,就是这些内容,重点是前一个页面通过属性向后一个页面传值。
协议传值
协议传值是通过代理来实现的,主要的应用场景是一个后一个页面向前一个页面传值。
第一步
首先设置一个协议,注意是在后一个页面设置这个协议
@protocol VCFourthDelegte <NSObject> -(void)ChangeImageView:(NSInteger)tag; @end
第二步
在后面这个页面设置属性用作代理
@property (nonatomic, weak) id<VCFifthDelegate> delegate; //这里尽量采用weak作为修饰符
第三步
在某一个位置触发代理事件,将需要传递的数据向前传递。
[self.delegate changeImageView:tap.view.tag]; [self.navigationController popViewControllerAnimated:YES];
第四步
在前一个视图控制器中间遵循协议并实现代理方法,以接收传递过来的数据。
- (void)changeImageView:(NSInteger)tag { self.tag = tag; [self.tableView reloadData]; }
第五步
不要忘了在前一个视图控制器推出下一个视图控制器的时候将后者的代理设置成自己
ViewController5* vc5 = [[ViewController5 alloc] init]; vc5.delegate = self; [self.navigationController pushViewController:vc5 animated:YES];
我们主要是要将后面的视图控制器作为前一个视图控制器的代理,让后者为前者完成一些底层的内容从而改变前者的内容。
Block传值
block传值同样用于后一个页面向前一个页面传值。
第一步
在后一个页面中定义一个Block属性
@property (nonatomic, copy) void(^reutnblock)(NSString* temp, NSInteger num);
第二步
设置一个事件来触发返回上一级视图控制器的时候,使用第一步定义的Block,把需要传递的值放在^Block中间
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 40)]; self.label.textColor = [UIColor whiteColor]; self.label.text = @"123412342"; NSLog(@"%ld", _tag); _btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];\ self.btn1.frame = CGRectMake(100, 100, 100, 100); self.view.backgroundColor = [UIColor whiteColor]; self.btn1.backgroundColor = [UIColor redColor]; [self.btn1 setTitle:@"state" forState:UIControlStateNormal]; [self.view addSubview:self.btn1]; [self.btn1 addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside]; self.label.backgroundColor = UIColor.redColor; [self.view addSubview:_label]; // Do any additional setup after loading the view. } -(void)press{ self.reutnblock(self.label.text, --_tag); // 重点部分 [self.navigationController popViewControllerAnimated:YES]; }
第三步
在前一个页面跳转到后一个页面的事件函数中,调用后一个页面中的Block这个属性
-(void)press { secondViewController* second = [[secondViewController alloc] init]; second.reutnblock = ^(NSString * _Nonnull temp, NSInteger num) { self.label.text = temp; self.num = num; }; [self.navigationController pushViewController:second animated:YES]; }
下面给出一个通过Block实现的一个效果图,这里我们通过这段代码将后一个页面的label中的文字传到了前一个视图控制器中,从而实现了一个从后向前传值的一个效果。
通知传值
通知传值主要是通过一个通知中心进行传值,可以跨域多个页面进行一个传值。我在实现一个深色模式的时候采用了这种传值方式,通过一个通知中心将一个全局变量传给其他几个页面,一般也是从后面的页面传给前面的页面。
第一个步骤
创建并且发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"notice" object:nil userInfo:@{@"first":@"123"}];
现在介绍一下这个方法的几个参数:
NSNotificationCenter: NSNotificationCenter
是一个单例对象,用于在应用程序内传递消息。它允许一个对象发布通知,其他对象可以注册为该通知的观察者,以便在通知发布时收到消息。defaultCenter:
这是 NSNotificationCenter 的类方法,返回应用程序的默认通知中心实例。postNotificationName:object:userInfo::
这是 NSNotificationCenter 的实例方法,用于发布通知。postNotificationName:
要发布的通知的名称。在这里,通知的名称是 “notice”。object:
通知的发送者,可以是任何对象。这里传入 nil,表示没有特定的发送者。userInfo:
一个字典,包含通知的附加信息。在这里,字典包含一个键值对 @“first”: @“123”。
第二个步骤
注册一个观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receive:) name:@"notice" object:nil];
介绍一下这个函数的内容
第三个步骤
接收者对象需要实现一个方法,用于处理接收到的通知。这个方法是在观察者注册时通过selector参数指定的。当通知被发送时,通知中心会调用这个方法,并传递相关的信息给观察者。
-(void)receive:(NSNotification*) send { NSLog(@"接受通知"); NSLog(@"%@", send.userInfo[@"first"]); self.label.text = send.userInfo[@"first"]; }
第四个步骤
在接收者对象被销毁之前,需要将其从通知中心中移除,避免出现潜在的内存泄漏。可以使用NSNotificationCenter的removeObserver:系列方法来移除观察者。
-(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
下面就是相关的一个实现效果,我将字符串123传递到前一个Label中,成功实现了一个通知传值
KVO传值
概述
KVO全称KeyValueObserve
也就是观察者模式,是apple提供的一套事件通知机制.允许对象监听另一个对应特殊属性的改变,并在改变时接受到该事件.一般继承自NSObject
的对象都默认是支持KVO。
KVO(Key-Value-Observing,键值观察),即观察关键字的值的变化。首先在子页面中声明一个待观察的属性,在返回主页面之前修改该属性的值。在主页面中提前分配并初始化子页面,并且注册对子页面中对应属性的观察者。在从子页面返回主页面之前,通过修改观察者属性的值,在主页面中就能自动检测到这个改变,从而读取子页面的数据。KVO只对属性发生作用。
传递方向
主要也是从后往前。
这里我们主要演示的是一个从A页面通过KVO来监听B页面的一个值,下面来看具体的实现流程。
使用步骤
第一步
注册观察者
同样和上面的通知传值一样,在触发事件的函数中注册我们的观察者。
@property (nonatomic, strong) secondViewController* second; //这里现在第一个页面中设置第二个页面作为自己的一个属性 - (void)press { //这里我才用了一个按钮来触发事件 //[self willChangeValueForKey:@"ary"]; self.second = [[secondViewController alloc] init]; [self.second addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; [self.navigationController pushViewController:self.second animated:YES]; }
这里解释一下这几个参数的含义:
P1: 观察者,该对象必须实现 该对象必须实现 observeValueForKeyPath:ofObject:change:context: 方法。
P2:要观察的属性。
P3:选择监听返回的值的类型:enum {NSKeyValueObservingOptionNew
接收方法中使用change参数传入变化后的新值NSKeyValueObservingOptionOld
接收方法中使用change参数传入变化前的旧值NSKeyValueObservingOptionInitial change
参数内容会包含新值NSKeyValueObservingOptionPrior
如果加入这个参数,接收方法会在变化前后分别调用一次,共两次,变化前的通知change参数
};P4: 传入任意类型的对象,在接受消息回调的代码中可以接受这个对象
第二步
接受通知,使用方法observeValueForKeyPath:ofObject:change:context:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"userName"]) { self.label.text = self.second.userName; NSLog(@"old text:%@ new text:%@", [change objectForKey:NSKeyValueChangeOldKey], [change objectForKey:NSKeyValueChangeNewKey]); } }
第三步
删除KVO
- (void)dealloc { [self removeObserver:self forKeyPath:@"userName"]; }
这样就可以实现我们的KVO传值的效果,这里就可以看到我们在的子页面修改值后,主页面的UILabel出现了一个改变,这样我们就实现了一个传值。
tips:
- 这种方式不可以实现对于数组元素的一个监听,因为KVO是对于setter方法的监听,而数组的addObject方法并不是setter方法的内容,所以无法通过上述方法实现对于数组的一个监听。
- 不使用时要移除KVO。
总结
iOS多界面传值主要就是通过这五种方式来实现,笔者这里只是简单学习了如何使用这几种传值方式的用法