界面通信

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了界面通信相关的知识,希望对你有一定的参考价值。

属性传值、协议传值、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修饰变量来防?循环引?

以上是关于界面通信的主要内容,如果未能解决你的问题,请参考以下文章

无法通过接口获取与片段通信的活动

如何在 BottomNavigationView 的片段上打开搜索界面?

在一些片段之间填充对象变量的最佳方法

如何在嵌套片段内的两个子片段之间进行通信

与 viewpager 内的片段的父片段通信

微信小程序代码片段