属性传值、协议传值、Block传值
?、属性传值
/**
* 属性传值
1、属性传值用于第一个界面向第二个界面传送值
2、明确二者联系的桥梁,也就是触发跳转的地方
3、明确传输的值 类型是什么
4、在第二个视图控制器内部声明相对应类型的属性,来接收传输的值
5、在第二个界面使用传入的值
*/
//第?步:在SecondViewController.h?定义?个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];
}
//第三步:在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];
}
?、协议传值
第?步:声明协议
第?步:声明代理?
第三步:执?协议?法
第四步:签订协议
第五步:指定代理?
第六步:实现协议?法
//1、在 FourthViewController.h?声明协议
//UI中的协议名称为 当前类名 + Delegate
@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];
}
//4、接收(签订)协议
@interface ThirdViewController : UIViewController<FourthViewControllerDelegate>
//5、指定当前对象为代理人
- (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;
}
三、Block传值
- block是匿名函数,能够实现函数回调功能
- ?于页?之间通信,同时可以进?传值
/**
* 1、Block是一种数据类型,并且是一种自定义的数据类型
2、Block的标志是^(托字符)
3、Block是匿名函数,TA与函数最主要的区别在于,函数在编译期就已经知道封装了什么功能,但是Block只有当执行时才知道内部封装的功能,所以说Block更加灵活多变
4、Block的作用也是封装代码段来实现具体的功能
5、既然Block是匿名函数,所以赋值时,不能将函数名直接赋值,初值为函数的实现体。
*/
void(^block)(void) = ^(void)
{
};
其中:
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);
};
block1();//执?block
//2.有参?返回值
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 @"?参有返回值";
};
NSLog(@"block3 = %@“,block3());
//4.有参有返回值类型的block
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();
NSLog(@"a = %d, count = %d",a, count);
- 使?场景类似协议传值,都是解决从后?个页?往前?个页?传值问题
Block传值的两种方式:
- ?式?: 使?block属性实现回调传值
#warning 第?步
//在第?个???声明block属性
typedef void (^BaDa)(NSString *);
typedef void (^FuFu)(UIColor *);
//Block声明成属性,必须使?copy,retain?效
@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];
}
#warning 第三步
//在第?个???,实现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 release];
}
#warning 第四步
//block内存管理
- (void)dealloc {
//释放Block有专门的方法
Block_release(_bada);
Block_release(_fufu);
[super dealloc];
}
- ?式?: 在?法中定义block实现回调传值
#warning 第?步
//在AppTool.h中重定义void(^)(NSString *string)类型的别名为AppToolBlock
typedef void(^AppToolBlock)(NSString *string);
#warning 第?步
//声明?法,在?法中封装block
-(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);
}
#warning 第四步
-(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);
运?结果: block = <__NSGlobalBlock__: 0x107321360>
• 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);
}
运?结果:firstBlock === <__NSMallocBlock__: 0│7ff838d14b70>
-(void)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修饰变量来防?循环引?
在arc下使?__week修饰变量来防?循环引?