iOS常用传值小结
***************************
##最简单的用第二个界面的label来显示第一个界面的textField中的文本
(一)属性传值—-前向后传值
1.我们首先要在RootViewController的基础上创建一个DetailViewController,然后我们要记住传值过程中用到什么类型就定义什么属性,因此我们需要在DetailViewController页面声明一个textString属性,来接收传过来的字符串,
/*
* 声明一个textString属性,用于接收传过来的字符串
* —- 属性传值
*/
@property (nonatomic, copy) NSString *textString;
2.接下来我们来创建显示的label
/*
* 创建label用于显示传过来的字符串
*/
-(void)createUIFrame{
UILabel *xianshiLab = [[UILabel alloc] initWithFrame:CGRectMake(20, 300, [UIScreen mainScreen].bounds.size.width - 40, 100)];
xianshiLab.backgroundColor = [UIColor greenColor];
xianshiLab.font = [UIFont systemFontOfSize:13.0f];
xianshiLab.numberOfLines = 0;
/*
* 使用属性传递得到的文本
*/
xianshiLab.text = self.textString;
[self.view addSubview:xianshiLab];
}
3.我们需要在RootViewController中引入DetailViewController同时还要声明一个属性来输入字符串(可选择)textField,
/*
* 声明一个textfield属性来输入字符串
*/
@property (nonatomic, copy) UITextField *textField;
创建button并给textField相关属性赋值
-(void)createUIFrame{
_textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 100, [UIScreen mainScreen].bounds.size.width-40, 40)];
_textField.borderStyle = UITextBorderStyleRoundedRect;
_textField.layer.borderColor = [UIColor blackColor].CGColor;
_textField.layer.borderWidth = 1.0f;
_textField.placeholder = @"请输入字符串";
[self.view addSubview:_textField];
/*
* 添加手势,取消键盘第一响应
*/
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
[self.view addGestureRecognizer:tap];
/*
* 创建button
*/
UIButton *pushBtn = [UIButton buttonWithType:UIButtonTypeCustom];
pushBtn.frame = CGRectMake(0, 0, 80, 40);
[pushBtn setTitle:@"跳转传值" forState:UIControlStateNormal];
pushBtn.titleLabel.font = [UIFont systemFontOfSize:16.0f];
pushBtn.center = self.view.center;
[pushBtn addTarget:self action:@selector(handlePush:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:pushBtn];
}
4.通过button的点击事件完成整个属性传值
pragma mark —– 点击事件—
-(void)handlePush:(UIButton *)sender{
DetailViewController *detailVC = [[DetailViewController alloc] init];
/*
* 属性传值
*/
detailVC.textString = self.textField.text;
[self.navigationController pushViewController:detailVC animated:YES];
}
-(void)handleTap{
[self.view endEditing:YES];
}
(二)代理传值
在项目中,我们经常遇到,当RootViewController页面Push到DetailViewController,而我们DetailViewController页面的一些信息想要回传(回调)到RootViewController,这时候就用到了回调
*需要注意DetailViewController页面定义协议和声明代理,RootViewController页面确认并实现代理。RootViewController作为DetailViewController的代理
1.首先我们在DetailViewController的.h文件中创建协议方法
/*
* 代理传值
*/
@class DetailViewController;
@protocol passingValueDelegate
@optional
-(void)viewController:(DetailViewController *)viewcontroller didPassingValueWithInfo:(id)info;
@end
/*
* 通过代理对象传值
*/
@property (nonatomic, assign) iddelegate;
2.在DetailViewController的.m中我们判定代理对象存在时,为其绑定相应的方法
/*
* 我们判定代理对象存在时,为其绑定相应方法
*/
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
/*
* 视图将要消失时,通过代理传值
* 首次判定代理是否存在,并且代理能够响应代理方法时,才执行代理方法
*/
if (self.delegate && [self.delegate respondsToSelector:@selector(viewController:didPassingValueWithInfo:)]) {
/*
* 传递当前视图的背景颜色
*/
[self.delegate viewController:self didPassingValueWithInfo:self.view.backgroundColor];
}
}
3.在RootViewController的.m文件中我们指定代理并让其执行代理的方法
pragma mark —– 点击事件—
-(void)handlePush:(UIButton *)sender{
DetailViewController *detailVC = [[DetailViewController alloc] init];
/*
* 代理传值 为detailVC指定代理对象
* /
detailVC.delegate = self;
[self.navigationController pushViewController:detailVC animated:YES];
}
-(void)viewController:(DetailViewController *)viewcontroller didPassingValueWithInfo:(id)info{
/*
* 把第二个视图的颜色传给第一个视图
*/
self.view.backgroundColor = info;
}
到这里就已经完成了整个过程
(三)回调传值
在iOS中,关于block的用法非常多,传值只是其中一个很小的用法,它在页面消失(或跳转)的瞬间完成传值。
1.我们要使用block首先要先在第二个视图控制器的.h文件中定义Block属性
typedef void(^returnBlock)(NSString *showText);
@interface SecondViewController : ViewController
//声明block 属性
@property (nonatomic,strong)returnBlock returnTextBlock;
//声明 调用方法
- (void) returnText: (returnBlock)block;
在这里我们第一行给要声明的Block重新定义了一个名字:ReturnTextBlock 随后均使用这个名字
第三行定义了一个Block属性
第四行是在第一个界面传进来一个Block语句块的函数(可不用,但加上会减少代码量)
2.接下来实现第二个视图控制器的方法就可以了
-(void) returnText:(returnBlock)block{
self.returnTextBlock = block;
}
-(void)viewDidDisappear:(BOOL)animated
{
//即将消失的时候
if (self.returnTextBlock !=nil) {
self.returnTextBlock(self.textField.text);
}
NSLog(@"======%@=======",self.returnTextBlock);
}
这里面第一个方法就是定义的那个方法,把传进来的Block语句块保存到本类的实例化变量returnTextBlock(.h重定义的属性中),然后寻找一个时机调用,这就是第二个方法,在视图即将消失时调用。
3.在第一个视图控制器中获得第二个视图控制器,并且用第二个来调用定义的属性
-(void)viewDidLoad {
[super viewDidLoad];
SecondViewController *secondVc = [[SecondViewController alloc] init];
[secondVc returnText:^(NSString *showText) {
NSLog(@"---------%@------------",showText);
self.secTextField.text = showText;
}];
self.secVc = secondVc;
self.secVc.delegate = self;
}
这样我们就可以完成整个的回调功能,从而达到了传值的目的。
链接一篇描述block回调挺有意思的文章:http://blog.csdn.net/mobanchengshuang/article/details/11751671
(四) 通知传值
*注意:谁要监听值的变化,谁就注册通知,通知的接收者必须存在
1.首先我们要在第二个控制器中进行相应操作
/*
* 注册通知
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tongzhi:) name:@"tongzhi" object:nil];
/*
* 接收通知传值
*/
-(void)tongzhi:(NSNotification *)text{
NSLog(@"%@",text.userInfo[@"textOne"]);
NSLog(@"--------接收到通知-------");
/*
* 移除通知
*/
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"tongzhi" object:nil];
}
2.在第一个控制器中执行点击监听方法
pragma mark —– 点击事件—
-(void)handlePush:(UIButton *)sender{
/*
* 通知传值
* 输入要发送的信息,同时将label的值通过button方法调用过去
*
* 添加字典,将label的值通过key值设置传递
*/
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:self.textFieldOne.text,@"textOne",self.textFieldTwo.text,@"textTwo", nil];
/*
* 创建通知
* 通过通知中心发送通知
*/
NSNotification *notifiction = [NSNotification notificationWithName:@"tongzhi" object:nil userInfo:dict];
[[NSNotificationCenter defaultCenter] postNotification:notifiction];
[self.navigationController pushViewController:detailVC animated:YES];
}
本地化存储,较为简单,将需要的信息存起来,用的时候取出来,最后释放即可:
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:dict forKey:@"login"];
[defaults synchronize];
释放:
NSUserDefaults * defaults =[NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:@"login"];
[defaults synchronize];
*另外还存在几种传值方式,但是我使用较少,几乎不用,所以无法进行总结***
(1)SharedApplication定义一个变量来传递(单例)
(2)通过文件 或者NSUserdefault来传递
//通过文件或者UserDefault方式存值(感觉不太适合此类传值,如果要用文件或者UserDefault方式存值的话,可以考虑此方式)
-(IBAction)userDefaultMethod:(id)sender {
if ([self notEmpty]) {
[[NSUserDefaults standardUserDefaults] setObject:self.nameTextField.text forKey:@"myNameText"];
[self dismissViewControllerAnimated:YES completion:nil];
}else{
[self showAlert];
}
}
在A控制器显示
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
//如果想测试通过UserDefault方式传值或者通过单例方式传值,取消以下注释即可
/*
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"myNameText"] length] != 0) {
self.nameLabel.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"myNameText"];
[[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"myNameText"];
}
DataSource *dataSource = [DataSource sharedDataSource];
if ([dataSource.myName length] != 0) {
self.nameLabel.text = dataSource.myName;
dataSource.myName = @"";
}
*/
}
(3)通过单例的class来传递
在B控制器
//通过单例方式传值(感觉不太适合此类传值,如果要用单例方式传值的话,可以考虑此方式)
-(IBAction)singletonMethod:(id)sender {
if ([self notEmpty]) {
DataSource *dataSource = [DataSource sharedDataSource];
dataSource.myName = self.nameTextField.text;
[self dismissViewControllerAnimated:YES completion:nil];
}else{
[self showAlert];
}
}
这里面用到了单例模式,编写了DataSource类。存放数据
#import
#import “DataSource.h”
@implementation DataSource
+(DataSource *)sharedDataSource{
static DataSource *dataSource = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
dataSource = [DataSource new];
});
return dataSource;
}
@end