属性传值、协议传值、Block传值
⼀、属性传值
/**
* 属性传值
1、属性传值用于第一个界面向第二个界面传送值
2、明确二者联系的桥梁,也就是触发跳转的地方
3、明确传输的值 类型是什么
4、在第二个视图控制器内部声明相对应类型的属性,来接收传输的值
5、在第二个界面使用传入的值
* 属性传值
1、属性传值用于第一个界面向第二个界面传送值
2、明确二者联系的桥梁,也就是触发跳转的地方
3、明确传输的值 类型是什么
4、在第二个视图控制器内部声明相对应类型的属性,来接收传输的值
5、在第二个界面使用传入的值
*/
//第⼀步:在SecondViewController.h⾥定义⼀个contents字符串属性来保存由第一个界面传过来的字符串内容
@interface SecondViewController :
UIViewController
@property(nonatomic,copy)NSString *contents;
@interface SecondViewController :
UIViewController
@property(nonatomic,copy)NSString *contents;
@end
//第⼆步:在点击FirstViewController按钮的⽅法⾥给SecondViewController的contents属性赋值
-(void)buttonAction:(UIButton *)button
{
NSLog(@"进⼊第⼆⻚");
SecondViewController *secondVC =
[[SecondViewController alloc] init];
secondVC.contents = self.label.text;
[self.navigationController
pushViewController:secondVC animated:YES];
[secondVC release];
-(void)buttonAction:(UIButton *)button
{
NSLog(@"进⼊第⼆⻚");
SecondViewController *secondVC =
[[SecondViewController alloc] init];
secondVC.contents = self.label.text;
[self.navigationController
pushViewController:secondVC animated:YES];
[secondVC release];
}
//第三步:在SecondViewController使⽤contents属性给textField赋值
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"第⼆⻚";
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(85, 200, 200, 40)];
self.textField.placeholder = @"请输⼊内容";
self.textField.text = self.contents;
self.textField.borderStyle =
UITextBorderStyleRoundedRect;
[self.view addSubview:self.textField];
[_textField release];
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"第⼆⻚";
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(85, 200, 200, 40)];
self.textField.placeholder = @"请输⼊内容";
self.textField.text = self.contents;
self.textField.borderStyle =
UITextBorderStyleRoundedRect;
[self.view addSubview:self.textField];
[_textField release];
}
⼆、协议传值
第⼀步:声明协议
第⼆步:声明代理⼈
第三步:执⾏协议⽅法
第四步:签订协议
第五步:指定代理⼈
第六步:实现协议⽅法
//1、在 FourthViewController.h⾥声明协议
//UI中的协议名称为 当前类名 + Delegate
@protocol FourthViewControllerDelegate <NSObject>
@protocol FourthViewControllerDelegate <NSObject>
//声明协议方法
@required //必须要实现的⽅法,默认是必须实现
- (void)pushValue:(NSString *)text;
@optional //可选实现的协议⽅法
- (void)pushColor:(UIColor *)color;
@end
//2、声明代理 必须是assign,使⽤retain,copy会导致循环引⽤问题
@property (nonatomic, assign) id<FourthViewControllerDelegate>delegate;
//3、执⾏协议⽅法
- (void)back {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(pushValue:)]) {
[self.delegate pushValue:self.textField.text];
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(pushColor:)]) {
[self.delegate pushColor:self.view.backgroundColor];
}
[self.navigationController popViewControllerAnimated:YES];
- (void)back {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(pushValue:)]) {
[self.delegate pushValue:self.textField.text];
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(pushColor:)]) {
[self.delegate pushColor:self.view.backgroundColor];
}
[self.navigationController popViewControllerAnimated:YES];
}
//4、接收(签订)协议
@interface ThirdViewController : UIViewController<FourthViewControllerDelegate>
//5、指定当前对象为代理人
- (void)push {
FourthViewController *fourthVC = [[FourthViewController alloc] init];
//指定第二个界面的代理对象为第一个视图控制器
fourthVC.delegate = self;
[self.navigationController pushViewController:fourthVC animated:YES];
[fourthVC release];
- (void)push {
FourthViewController *fourthVC = [[FourthViewController alloc] init];
//指定第二个界面的代理对象为第一个视图控制器
fourthVC.delegate = self;
[self.navigationController pushViewController:fourthVC animated:YES];
[fourthVC release];
}
//6、实现协议方法,并接收传过来的值
- (void)pushValue:(NSString *)text {
self.label.text = text;
}
- (void)pushColor:(UIColor *)color {
self.view.backgroundColor = color;
- (void)pushValue:(NSString *)text {
self.label.text = text;
}
- (void)pushColor:(UIColor *)color {
self.view.backgroundColor = color;
}
三、Block传值
- block是匿名函数,能够实现函数回调功能
- ⽤于页⾯之间通信,同时可以进⾏传值
/**
* 1、Block是一种数据类型,并且是一种自定义的数据类型
2、Block的标志是^(托字符)
3、Block是匿名函数,TA与函数最主要的区别在于,函数在编译期就已经知道封装了什么功能,但是Block只有当执行时才知道内部封装的功能,所以说Block更加灵活多变
4、Block的作用也是封装代码段来实现具体的功能
5、既然Block是匿名函数,所以赋值时,不能将函数名直接赋值,初值为函数的实现体。
* 1、Block是一种数据类型,并且是一种自定义的数据类型
2、Block的标志是^(托字符)
3、Block是匿名函数,TA与函数最主要的区别在于,函数在编译期就已经知道封装了什么功能,但是Block只有当执行时才知道内部封装的功能,所以说Block更加灵活多变
4、Block的作用也是封装代码段来实现具体的功能
5、既然Block是匿名函数,所以赋值时,不能将函数名直接赋值,初值为函数的实现体。
*/
void(^block)(void) = ^(void)
{
};
其中:
1.void(^block)(void)是类型
2.block是变量名
{
};
其中:
1.void(^block)(void)是类型
2.block是变量名
3.^(void){};是block实现
//1.⽆参⽆返回值类型的block
__block int a = 0;
void(^block1)(void) = ^(void)
{
//在block内部不能直接修改局部变量的值,
如果想修改必须声明成__block类型的变量
a ++;
NSLog(@"block1 %d",a);
};
__block int a = 0;
void(^block1)(void) = ^(void)
{
//在block内部不能直接修改局部变量的值,
如果想修改必须声明成__block类型的变量
a ++;
NSLog(@"block1 %d",a);
};
block1();//执⾏block
//2.有参⽆返回值
void(^block2)(int age, NSString *string) = ^(int
age, NSString *string)
{
NSLog(@"age = %d, text = %@", age, string);
};
void(^block2)(int age, NSString *string) = ^(int
age, NSString *string)
{
NSLog(@"age = %d, text = %@", age, string);
};
block2(20,@"⼩明");
//3.⽆参有返回值类型的block
NSString *(^block3)(void) = ^(void)
{
return @"⽆参有返回值";
};
NSString *(^block3)(void) = ^(void)
{
return @"⽆参有返回值";
};
NSLog(@"block3 = %@“,block3());
//4.有参有返回值类型的block
NSString *(^block4)(NSString *text) =
^(NSString *string)
{
return [string
stringByAppendingString:@"有返回值"];
};
NSString *(^block4)(NSString *text) =
^(NSString *string)
{
return [string
stringByAppendingString:@"有返回值"];
};
NSLog(@"block4 %@", block4(@"有参"));
__block int a = 6;
void (^testBlock)() = ^{
NSLog(@"%d",a);//Block内部可以访问局部变量的值
a = 9;//Block内部如果想修改外界局部变量的值,必须对变量进行__block修饰
count = 101;//Block内部可以直接修改全局变量的值,也可以直接访问全局变量的值
};
testBlock();
void (^testBlock)() = ^{
NSLog(@"%d",a);//Block内部可以访问局部变量的值
a = 9;//Block内部如果想修改外界局部变量的值,必须对变量进行__block修饰
count = 101;//Block内部可以直接修改全局变量的值,也可以直接访问全局变量的值
};
testBlock();
NSLog(@"a = %d, count = %d",a, count);
- 使⽤场景类似协议传值,都是解决从后⼀个页⾯往前⼀个页⾯传值问题
Block传值的两种方式:
- ⽅式⼀: 使⽤block属性实现回调传值
#warning 第⼀步
//在第⼆个⻚⾯⾥声明block属性
typedef void (^BaDa)(NSString *);
//在第⼆个⻚⾯⾥声明block属性
typedef void (^BaDa)(NSString *);
typedef void (^FuFu)(UIColor *);
//Block声明成属性,必须使⽤copy,retain⽆效
@property (nonatomic, copy) FuFu fufu;
@property (nonatomic, copy) FuFu fufu;
@property (nonatomic, copy) BaDa bada;
#warning 第⼆步
//在第⼆个⻚⾯⾥执⾏block回调,将所要传的值传给第⼀个⻚⾯
- (void)back {
//执行Block
if (self.bada != nil) {
self.bada(self.textField.text);
}
if (self.fufu != nil) {
self.fufu(self.view.backgroundColor);
}
[self.navigationController popViewControllerAnimated:YES];
//在第⼆个⻚⾯⾥执⾏block回调,将所要传的值传给第⼀个⻚⾯
- (void)back {
//执行Block
if (self.bada != nil) {
self.bada(self.textField.text);
}
if (self.fufu != nil) {
self.fufu(self.view.backgroundColor);
}
[self.navigationController popViewControllerAnimated:YES];
}
#warning 第三步
//在第⼀个⻚⾯⾥,实现block
//在第⼀个⻚⾯⾥,实现block
- (void)push {
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.bada = ^(NSString *str) {
self.label.text = str;
};
secondVC.fufu = ^(UIColor *color) {
self.view.backgroundColor = color;
};
[self.navigationController pushViewController:secondVC animated:YES];
secondVC.bada = ^(NSString *str) {
self.label.text = str;
};
secondVC.fufu = ^(UIColor *color) {
self.view.backgroundColor = color;
};
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
}
#warning 第四步
//block内存管理
- (void)dealloc {
//block内存管理
- (void)dealloc {
//释放Block有专门的方法
Block_release(_bada);
Block_release(_fufu);
[super dealloc];
Block_release(_fufu);
[super dealloc];
}
- ⽅式⼆: 在⽅法中定义block实现回调传值
#warning 第⼀步
//在AppTool.h中重定义void(^)(NSString *string)类型的别名为AppToolBlock
typedef void(^AppToolBlock)(NSString *string);
//在AppTool.h中重定义void(^)(NSString *string)类型的别名为AppToolBlock
typedef void(^AppToolBlock)(NSString *string);
#warning 第⼆步
//声明⽅法,在⽅法中封装block
-(void)sendNumber:(NSInteger )number andBlock:
-(void)sendNumber:(NSInteger )number andBlock:
(AppToolBlock)block;
#warning 第三步
//在AppTool.m实现⽅法,并执⾏block
-(void)sendNumber:(NSInteger )number andBlock:(AppToolBlock)block;
{
NSString *string = [NSString stringWithFormat:@"%ld",number];
block(string);
//在AppTool.m实现⽅法,并执⾏block
-(void)sendNumber:(NSInteger )number andBlock:(AppToolBlock)block;
{
NSString *string = [NSString stringWithFormat:@"%ld",number];
block(string);
}
#warning 第四步
-(void)buttonAction:(UIButton *)button
{
AppTool *appTool = [[AppTool alloc] init];
//执⾏⽅法,实现block并接收回传过来的string值
[appTool sendNumber:10086 andBlock:^(NSString *string) {
self.label.text = string;
}];
-(void)buttonAction:(UIButton *)button
{
AppTool *appTool = [[AppTool alloc] init];
//执⾏⽅法,实现block并接收回传过来的string值
[appTool sendNumber:10086 andBlock:^(NSString *string) {
self.label.text = string;
}];
}
四、Block内存管理
• 没有使⽤局部变量的block内存存储在全局区
void(^block)(void) = ^(void)
{
};
NSLog(@"block = %@“,block);
void(^block)(void) = ^(void)
{
};
NSLog(@"block = %@“,block);
运⾏结果: block = <__NSGlobalBlock__: 0x107321360>
• block内部使⽤局部变量的时候内存存储在栈区
__block int a = 0;
void(^block)(void) = ^(void)
{
a = 10;
};
NSLog(@"block = %@",block);
__block int a = 0;
void(^block)(void) = ^(void)
{
a = 10;
};
NSLog(@"block = %@",block);
运⾏结果: block = <__NSStackBlock__: 0│7fff57a920c8>
- 当block变量定义为属性的时候,必须使⽤copy修饰,retain ⽆效,即retain和assign会造成野指针问题.
- 当对block进⾏copy操作的时候,此时block的内存区域为堆 区.
- 当不使⽤block时需要使⽤Block_Release()进⾏销毁.
- 注意:关于block内存管理上的三个区域,在arc和⾮arc下还是 有区别的
//block会造成self的引⽤计数+1
-(void)pushAction:(UIButton *)button
{
self.FirstBlock([UIColor yellowColor]);
NSLog(@"firstBlock === %@",self.FirstBlock);
}
{
self.FirstBlock([UIColor yellowColor]);
NSLog(@"firstBlock === %@",self.FirstBlock);
}
运⾏结果:firstBlock === <__NSMallocBlock__: 0│7ff838d14b70>
-(void)dealloc
{
Block_release(_FirstBlock);
[super dealloc];
{
Block_release(_FirstBlock);
[super dealloc];
}
//block会造成self的引⽤计数+1,使⽤__block 修饰变量来解决block循环引⽤问题
SecondViewController *secondVC = [[SecondViewController alloc] init];
__block FirstViewController *firstVC = self;
secondVC.SecondBlock = ^(NSString *string){
firstVC.label.text = string;
};
注意:
在⾮arc下使⽤__block修饰变量来防⽌循环引⽤
SecondViewController *secondVC = [[SecondViewController alloc] init];
__block FirstViewController *firstVC = self;
secondVC.SecondBlock = ^(NSString *string){
firstVC.label.text = string;
};
注意:
在⾮arc下使⽤__block修饰变量来防⽌循环引⽤
在arc下使⽤__week修饰变量来防⽌循环引⽤