• 界面通信


    属性传值、协议传值、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修饰变量来防⽌循环引⽤
  • 相关阅读:
    ajax原理和XmlHttpRequest对象
    在vue项目中 如何定义全局变量 全局函数
    杂乱知识 -- 记录工作或学习中遇到的一些点
    JavaScript中的数组遍历forEach()与map()方法以及兼容写法
    cookie的存取删
    微信小程序中公用内容
    mysql 多实例
    yum 安装和卸载
    rpm 安装卸载
    git blame
  • 原文地址:https://www.cnblogs.com/Walking-Jin/p/5210875.html
Copyright © 2020-2023  润新知