• iOS界面间传值


    知识点大纲

    (1) 什么是界面传值?

    (2) 正向传值

    (3) 代理传值

    (4) 单例传值

    (5) 通知传值

    (6) 代码块传值

    1.什么是界面传值?

    绝大多数应用都是由多个界面构成的,需要在界面之间传输数据,这就是界面传值。

    2. 正向传值

    实例:登陆界面创建主界面,登陆界面的用户名传递到主界面

    分析:A界面创建B界面,A界面的值传递到B界面

    如何实现?

    》在B界面中添加属性,用来保存用户名

    @interface MainViewController : UIViewController

    // 定义了可以接受其他界面传过来的值

      

     @property (nonatomic,copy) NSString *userName;
    
     @end

    》A界面中

        // 主界面

       

     MainViewController *mainVC = [[MainViewController alloc] init];

        // 注意:界面切换前传值

       

     mainVC.userName = @"hehe";

        // 跳转

       

     [self presentViewController:mainVC animated:YES completion:nil];

    》B界面中

        //显示传过来的用户名

       

     UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 200, 30)];
    
        nameLabel.text = [NSString stringWithFormat:@"用户名是: %@",_username];
    
        [self.view addSubview:nameLabel];

    3.反向传值(代理)

    代理传值六步走:

    // A界面创建B界面, B把值(颜色)传回给A界面

        MainViewController                                    ConfigViewController

     

    (1) 第一步,制定协议(哪里通知代理)

    //因为是ConfigViewController其他界面发送消息

    //  1. 告诉其他界面我要给你发送什么消息

    //  2. 确保其他实现了消息对应的方法

    // 声明协议和协议方法

    @protocol ConfigViewControllerDelegate <NSObject>

    // 最好以类型开头+方法名

    // 在遵守协议的其他类实现方法(即只声明不实现)

    -(void)conifgViewControllerWithBackgroundColor:(UIColor *)color;
    
    @end
     
    @interface ConfigViewController : UIViewController

    (2) 第二步,定义属性

    // 作用: 保存主界面的指针

    // 为什么保存, 最后给主界面发送消息修改字体

    // 细节1: weak 确保不会循环引用

    // 细节2: id 如果是id, 能传入任意界面了

    // 细节3: 遵守协议意味着可以任意对象

    @property (nonatomic,weak) id<ConfigViewControllerDelegate> delegate;
    
    
    @end
     

    (3) 第三步,通知代理

    // 通知代理(其实就是调用方法)

    // 判断是否实现了代理方法

    if ([self.delegate respondsToSelector:@selector(changeFontSize:)]) {
    
        [self.delegate changeFontSize:fontTextField.text.intValue]; 
    
    }

    (4) 第四步,遵守协议 

    @interface MainViewController () <ConfigViewControllerDelegate>
     

     //切换到配置界面

        ConfigViewController *configVC = [[ConfigViewController alloc] init];

        (5) 第五步,设置成为代理

        // 作用: 把当前界面的指针传到configVC中

        // 为啥: 希望配置界面中背景颜色改变通知主界面

        configVC.delegate = self;
    
        
    
        [self presentViewController: configVC animated:YES completion:nil];
     

    (6) 第六步,实现代理方法(具体方法的实现)

    - (void)conifgViewControllerWithBackgroundColor:(UIColor *)color{
    
        NSLog(@"实现的代理方法");
    
        self.view.backgroundColor = color;
    
    }
     

     

    》在声明代理属性时

    // 不能使用strong,避免VC调用sVC,然后sVC再调用VC形成循环引用,内存无法释放

    @property (nonatomic,weak) id<SecondViewControllerDelegate> delegate;

    (4) 单例传值(1对N)

    需求:A(登陆)->B->C->D->E->F(用户信息)

    需要A中的数据在F界面中显示;

    需要在每个界面中都显示“今天脱口秀”;

    解决:使用单例传值

    /** 懒汉式(真正用到的时候才加载) 饿汉式(程序一启动就加载)

     *  单例模式顾名思义就是只有一个实例,它确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。它经常用来做应用程序级别的共享资源控制。这个模式使用频率非常高,通过一个单例类,可以实现不同view之间的参数传递

     */

    实现:

    》创建一个单例类DataClass
    
    @interface DataClass : NSObject

     // 定义要使用的属性

      @property (nonatomic,copy) NSString *user;

      @property (nonatomic,strong) NSString *passwd;

      // 类方法

      + (instancetype)shareData;

      @end

    // 关键
    
        // 第一次执行: shareData为空, 会申请一个对象
    
        // 以后执行: shareData不为空, 直接返回以前创建的对象
    
    static DataClass *shareData = nil;
    
     
    
    // 表示获取一个共享的实例
    
        + (instancetype)shareData{
    
            if (shareData == nil) {
    
                shareData = [[DataClass alloc] init];
    
            }
    
            return shareData;
    
        }
       // alloc方法内部会调用这个方法
    
    // 最好实现重写这个方法,避免在实例化的时候用到了alloc + init
    
        + (instancetype)allocWithZone:(struct _NSZone *)zone{
    
            if (shareData == nil) {
    
                shareData = [super allocWithZone:zone];
    
            }
    
            return shareData;
    
        }
    
    //要求非常高单例类往往重写
    
    //  alloc,dealloc,retain,release,
    
    //  autorelease,copyWithZone
    》存储值
    
      DataClass *sharData = [DataClass shareData];
    
        sharData.user = @"单例模式";
    
        sharData.passwd = @"123321";
    
    》取值
    
        DataClass *dataShare = [DataClass shareData];
    
        NSLog(@"%@",dataShare);

    (5) 通知传值(1对N)

    A - B - C - D - E - F - G(通知A为红色,B界面为蓝色,C界面为黑色…)
    
     需求: 配置界面要换皮肤(背景颜色),其他界面相应
    
    实现:
    
    》配置界面中,发送换皮肤的通知   
    
        // 获取系统通知类的单例对象
    
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    
        // 发出一个通知
    
        // 参数Name: 通知的名字
    
        // 参数object: 要发给那个对象, nil表示不限制对象
    
        // 参数userInfo: 通知附加的信息, 皮肤颜色传过去
    
    // 原型[center postNotificationName:(NSString *) object:(id) userInfo:(NSDictionary *)];
    
        [center postNotificationName:@"color" object:nil userInfo:@{@"color":[UIColor magentaColor]];
    
     
    
    》其他界面获取到通知,切换背景
    
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    
        // 获取通知
    
        // 参数addObserver: 观察者,监听者
    
        // 参数selector: 获取到通知后的处理方法
    
        // 参数name: 通知的名字
    
        // 参数object: 要接受那个对象,nil表示不限制对象
    
        [center addObserver:self selector:@selector(centerTest:) name:@"color" object:nil];
    
     
    
    // 注意: 参数类型不是NSNotificationCenter
    
    - (void)centerTest:(NSNotification *)notification{
    
    // 获取通知中附加的信息
    
        NSLog(@"FirstViewController >> %@",notification.userInfo[@"color"]);
    
     
    
        self.view.backgroundColor = notification.userInfo[@"color"];
    
    }
    
    给不同界面发送通知
    
    [center postNotificationName:@"button" object:nil userInfo:@{@"button":@"yes",@"fVC":[UIColor brownColor],@"sVC":[UIColor cyanColor],@"tVC":[UIColor orangeColor]}];

    (6) 代码块传值

    1> 如何定义block变量(block是一种数据类型)
    
     int (^sumBlock)(int, int);
    
     void (^myBlock)();

    代码块传值三步走:

    // A界面创建B界面, B界面把背景颜色传回给A界面
    
    实现:
    
    》第一步
    
    声明代码块变量,并声明set方法
    
    @property (nonatomic,copy) void (^changeBackColor)(UIColor *color);
    
    - (void)setChangeBackColor:(void (^)(UIColor *))changeBackColor;
    三小步:
    
    > 模拟要实现的功能方法
    
        // 模拟要实现的功能
     - (void)changeBackColor:(UIColor *)color{
    
                self.view.backgroundColor = color;
    
        }
    
      > 将方法转为函数 
    
    // 将方法转为函数
    
            void changeBackColor(UIColor *color){
    
                self.view.backgroundColor = color;
    
            }
    
      > 将函数转为代码块
    
    // 将函数转为代码块
    
            void (^changeBackColor)(UIColor *color) = ^(UIColor *color){
    
                self.view.backgroundColor = color;
    
            };
    
     
    
    》第二步
    
    代码块的调用
    
    __weak typeof(self) weakSelf = self;
    
        // 代码块的调用,设置背景
    
        if (weakSelf.changeBackColor) { // 判断代码块是否为空
    
            NSArray *colors = @[[UIColor yellowColor],
    
                                [UIColor blueColor],
    
                                [UIColor greenColor]];
    
            // 代码块的调用
    
    // 产生随机数arc4random()
    
            weakSelf.changeBackColor(colors[arc4random()%3]);
    
        }
    
     
    
    》第三步
    
         设置代码块中具体操作
    
    // 把代码块作为参数传递
    
        [mVC setChangeBackColor:^(UIColor *color) { 
    
     
    
            self.view.backgroundColor = color;
    
        }];

        /**

         1、默认strong,可选weak。strong下不管成员变量还是property,每次使用指针指向一个对象,等于自动调用retain(), 并对旧对象调用release(),所以设为nil等于release。

         2、只要某个对象被任一strong指针指向,那么它将不会被销毁,否则立即释放,不用等runloop结束。所有strong指针变量不需要在dealloc中手动设为nil,ios会自动处理,debug可以看到全部被置为nil,最先声明的变量最后调用dealloc释放。

         

         3、官方建议IBOutlet加上__weak,实际上不用加也会自动释放;

         

         4、优先使用私有成员变量,除非需要公开属性才用property。

         

         5、避免循环引用,否则手动设置nil释放。

         

         6、block方法常用声明:@property (copy) void(^MyBlock)(void); 如果超出当前作用域之后仍然继续使用block,那么最好使用copy关键字,拷贝到堆区,防止栈区变量销毁。

         

         7、创建block匿名函数之前一般需要对self进行weak化,否则造成循环引用无法释放controller:

              __weak typeof(self) weakSelf = self;

         引用实例变量也会造成self的强引用,实例变量要用weakSelf->实例变量 的方式来访问

         */

  • 相关阅读:
    一文说透 Spring 循环依赖问题
    git修改已经push的commit message
    Connection Timeout 和CommandTimeout
    mvc 当中 [ValidateAntiForgeryToken] 的作用及用法
    mvc 当中 [ValidateAntiForgeryToken] 的作用及用法
    asp.net mvc与asp.net core Ajax删除操作delete中带ValidateAntiForgeryToken实例
    VS2017秘钥
    Sql server 2008 R2 配置管理工具服务显示远程过程调用失败:0x800706be
    SQL Server 2008找不到SQL Server配置管理器的问题
    如何为SQL Server2008添加登录账户并配置权限
  • 原文地址:https://www.cnblogs.com/vkSwift/p/12916484.html
Copyright © 2020-2023  润新知