iOS开发的界面传值主要有:属性传值、代理传值、代码块传值、单例传值、KVO传值、通知传值。
下面通过代码举例介绍这6种传值方式
属性传值
假设有A和B两个视图控制器,现在需要从A传值到B,那么首先在B.h文件中声明一个text属性,用来从A传值到B。然后去到A,先导入B.h文件,创建一个B的对象,然后给该对象的text属性赋值,再到B中输出text,会发现text值已从A传到了B,这就是属性传值。
//B的头文件
@interface BViewController : UIViewController
@property (nonatomic,strong)NSString *text;
@end
//A中有一个推送到B的方法,首先得导入B.h
- (void)nextAction {
BViewController *bvc = [[BViewController alloc] init];
bvc.text = @"ABC";//推送的时候给text赋值
[self presentViewController:bvc animated:YES completion:^{
}];
//在B中输出text
NSLog(@"text=%@",self.text);//输出结果是:text = ABC
单例传值
单例传值的实现思路是:首先创建一个C单例类,然后声明一个要传给A的属性name,同时在C中给name赋值。然后去到A中,先导入C.h头文件,创建一个C对象,然后输出C对象的name属性。
//C的头文件
@interface CViewController : UIViewController
@property (nonatomic,strong)NSString *name;
+ (CViewController *)shareInstance;
@end
//C.m文件中,实现创建单例类的一些操作
//声明一个静态全局cvc对象,并且赋值nil
static CViewController *cvc = nil;
@interface CViewController ()<NSCopying>//需要遵循NSCopying协议
@end
@implementation CViewController
+ (CViewController *)shareInstance {
if (cvc == nil) {
cvc = [[CViewController alloc] init];
}
// return self->cvc;
return cvc;
}
+ (id)allocWithZone:(struct _NSZone *)zone {
@synchronized (self) {
if (cvc == nil) {
cvc = [super allocWithZone:zone];
}
}
return cvc;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
//返回A时调用的方法
- (void)nextAction {
self.name = @"ZCQ";//返回的时候给name赋值
[self dismissViewControllerAnimated:YES completion:^{
}];
}
//到A中创建一个C对象并且输出C的属性
- (void)viewWillAppear:(BOOL)animated {
CViewController *cvc = [[CViewController alloc] init];
NSLog(@"%@",cvc.name);//结果是:ZCQ
}
代理传值
代理传值的实现思路是:在D中声明一个协议,该协议里包含一些方法,然后声明一个代理属性,在D中需要在判断代理是否存在及是否遵循协议。然后回到A中遵循该协议并且实现协议里声明的方法从而实现传值。
D.h文件
@protocol passValue <NSObject>
- (void)passOnValue:(NSString *)text;//注意这里的参数跟代码块的区别!!!
@end
@interface DViewController : UIViewController
//@property (nonatomic,strong)NSString *textString;
@property (nonatomic,assign)id<passValue>delegate;
@end
//回到A的方法
- (void)nextAction {
//判断代理是否存在并且是否遵循该协议
if (self.delegate && [self.delegate conformsToProtocol:@protocol(passValue)]) {
[self.delegate passOnValue:@"YF"];//如果存在,则调用协议里的方法
}
[self dismissViewControllerAnimated:YES completion:^{
}];
}
//回到A.m文件
- (void)nextAction {//去到D的方法
DViewController *dvc = [[DViewController alloc] init];
dvc.delegate = self;//把A作为dvc的代理
[self presentViewController:dvc animated:YES completion:^{
}];
}
//实现协议里的方法
- (void)passOnValue:(NSString *)text {
NSLog(@"Dtext = %@",text);//输出结果是:Dtext = YF
}
代码块传值
代码块传值的实现思路是:在E中定义一个带参数的代码块,并且声明一个该代码块类型的属性。在返回A的方法中调用该代码块,回到A创建E的对象并且调用代码块。
//E.h文件中
typedef void(^PassValue)(NSString *text);//代码块的参数写法与普通方法的参数写法不一样(NSString *)text
@interface EViewController : UIViewController
@property (nonatomic,copy)PassValue passValue;//内存管理:copy
@end
//E.m文件中
- (void)nextAction {
//返回A的方法,同时给block赋值
self.passValue(@"ZCQYF");//传值
[self dismissViewControllerAnimated:YES completion:^{
}];
}
//A.m文件中
//首先需要声明一个全局E类型的属性并且在viewDidLoad中初始化
_evc = [[EViewController alloc] init];
//在viewWillAppear中
- (void)viewWillAppear:(BOOL)animated {
-
_evc.passValue = ^(NSString *text){
NSLog(@"Etext = %@",text);//输出结果:ZCQYF
};
}
//去到E的方法
- (void)nextAction {
[self presentViewController:_evc animated:YES completion:^{
}];
}
KVO传值
创建一个F,在A中观察E中的name属性(注册观察者、定义KVO方法回调、移除观察者),去到F中,在回到A的方法改变属性的值,可以看到A中输出打印变化后的值,这就是KVO传值。
//F.h文件中声明一个要被观察的属性
@interface FViewController : UIViewController
@property (nonatomic,strong)NSString *name;
@end
//F.m文件中,在返回A的方法中改变name的值
- (void)nextAction {
[self setValue:@"ZCQ" forKey:@"_name"];//设置name的值为"ZCQ"
[self dismissViewControllerAnimated:YES completion:^{
}];
}
//回到A.m文件中,viewDidLoad方法中,
_fvc = [[FViewController alloc] init];//已经声明过的_fvc属性
//在viewDidLoad注册观察者
[_fvc addObserver:self forKeyPath:@"_name" options:NSKeyValueObservingOptionNew context:nil];
//定义观察者的方法回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"%@",[change objectForKey:NSKeyValueChangeNewKey]); //输出结果是:ZCQ
}
- (void)dealloc {
NSLog(@"移除观察者");
[_fvc removeObserver:self forKeyPath:@"_name"];
}
通知传值
通知传值实现思路:把要传的值放在userInfo中,通过通知中心这个单例发送通知、添加观察者、移除观察者。
//G.m文件返回A的方法
- (void)nextAction {
[[NSNotificationCenter defaultCenter] postNotificationName:@"通知" object:self userInfo:@{@"name":@"YF"}];//通知中心发送中心
[self dismissViewControllerAnimated:YES completion:^{
}];
}
//A.m的viewDidLoad
//通知中心注册观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shows:) name:@"通知" object:nil];
//方法回调
- (void)shows:(NSNotification *)notification {
NSLog(@"%@",notification.userInfo[@"name"]);//输出结果是:YF
}
//不要忘了移除观察者,同样也是在通知中心完成
- (void)dealloc {
NSLog(@"移除观察者");
[[NSNotificationCenter defaultCenter] removeObserver:self];
}