【iOS】多界面传值(五大传值方式)

【iOS】多界面传值(五大传值方式)

文章目录

  • 【iOS】多界面传值(五大传值方式)
    • 属性传值(Property)
    • 协议传值(Delegation)
    • 通知传值(NSNotification)
    • Block传值
    • 单例(Singleton)
    • 总结

属性传值(Property)

属性传值是一种正向传值的方式,即通过访问后一个视图控制器的属性,通过这个属性从前一个界面向后一个界面进行传值

我们直接讲解其步骤:

  1. 首先在后一个界面的.h文件定义属性

    @interface TargetViewController : UIViewController
     
    @property NSString* PropertyRecieved;
     
    @end
    
  2. 之后在前一个界面对当后一个界面将弹出时对这个属性进行复刻

    TargetViewController *targetVC = [[TargetViewController alloc] init];
    targetVC.PropertyRexieved = @"Hello, World!";
    [self.navigationController pushViewController:targetVC animated:YES];
    

协议传值(Delegation)

也称作代理传值,与属性传值相反,这是一种反向传值的方法,将后一个界面传值给前一个界面,本质是用协议中定义的方法来进行传值的

  1. 先要在后一个界面定义一个用于传值的协议与其代理属性

    // BViewController.h
    
    @protocol BViewControllerDelegate <NSObject>
    - (void)didReceiveData:(NSString *)data;
    @end
    
    @interface BViewController : UIViewController
    
    @property (nonatomic, weak) id<BViewControllerDelegate> delegate;
    
    @end
    
  2. 在前一个视图中遵守协议,设置代理并实现代理的方法,在后一个界面触发回调

    // AViewController.h
    #import "BViewController.h"
    
    @interface AViewController : UIViewController <BViewControllerDelegate>
    @end
      
      
    // AViewController.m
    BViewController *bVC = [[BViewController alloc] init];
    bVC.delegate = self;
    [self.navigationController pushViewController:bVC animated:YES];
    
    
    - (void)didReceiveData:(NSString *)data {
        NSLog(@"收到数据:%@", data);
    }
    
    // BViewController.m (传值的时候触发)
    if ([self.delegate respondsToSelector:@selector(didReceiveData:)]) {
        [self.delegate didReceiveData:@"我是传回来的数据"];
    }
    

通知传值(NSNotification)

通知传值是通过NSNotificationCenter实现的广播机制,一处发出了消息,任何监听这个消息的地方都可以收到,一般适合多个界面或者模块之间的状态同步

  1. 注册监听者,一旦有人发出名为"DarkModeChanged"的通知,就执行selector中的方法

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleDarkModeChange:)
                                                 name:@"DarkModeChanged"
                                               object:nil];
    
  2. 发送通知,在源视图中进行通知的发送,userInfo即为所要传的数据(是一个字典)

    [[NSNotificationCenter defaultCenter] postNotificationName:@"DarkModeChanged"
                                                        object:nil
                                                      userInfo:@{@"isDark": @(YES)}];
    
  3. 响应通知,处理所传来的值。执行相关的操作

    - (void)handleDarkModeChange:(NSNotification *)notification {
        NSDictionary *info = notification.userInfo;
        BOOL isDark = [info[@"isDark"] boolValue];
        
        // 根据是否是暗黑模式,更新界面
        self.view.backgroundColor = isDark ? [UIColor blackColor] : [UIColor whiteColor];
    }
    
  4. 移除监听(可选)

    - (void)dealloc {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    

    防止内存泄漏,当视图销毁时移除监听,不然系统还会给已经释放的对象发消息,导致崩溃

Block传值

Block传值的用途与协议传值有点相似,主要都是用于从后一个控制器向前一个控制器传值

Block 传值是通过在一个控制器中定义一个 Block(类似函数),另一个控制器在跳转前将 Block 实现赋值,最终在需要的时候回调它,从而实现传值。

  1. 在后一个控制器声明一个Block属性(发出方)

    // BViewController.h
    
    @interface BViewController : UIViewController
    
    @property (nonatomic, copy) void (^dataBlock)(NSString *data);
    
    @end
    
  2. 在前一个视图控制器设置Block的实现(接收方)

    // AViewController.m
    
    BViewController *bVC = [[BViewController alloc] init];
    bVC.dataBlock = ^(NSString *data) {
        NSLog(@"收到回传数据:%@", data);
    };
    [self.navigationController pushViewController:bVC animated:YES];
    
  3. 在后一个视图控制器需要时调用Block(回调传值)

    // BViewController.m
    
    if (self.dataBlock) {
        self.dataBlock(@"这是B传给A的值");
    }
    [self.navigationController popViewControllerAnimated:YES];
    

Block传值的方法更简洁,更适合用于一次性回调的方式

单例(Singleton)

单例传值是一种更为高级的数据传递方式,适用于在多个界面之间传递数据。通过创建一个全局唯一的共享对象(单例类)来实现多个界面共享和访问同一个数据的方式。

主要适用于多个界面中进行数据的共享,而无需在每个界面中进行传递

  1. 创建一个单例类(数据中心)

    // AppManager.h
    @interface AppManager : NSObject
    
    @property (nonatomic, strong) NSString *username; // 可传其他类型,如 BOOL isDarkMode
    
    + (instancetype)sharedManager;
    
    @end
    
    // AppManager.m
    @implementation AppManager
    
    + (instancetype)sharedManager {
        static AppManager *manager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [[AppManager alloc] init];
        });
        return manager;
    }
    
    @end
    

    这是一个全局对象,每次返回的都是同一个实例,可以放任何想共享的数据

  2. 在一个界面中设置数据

    [AppManager sharedManager].username = @"小明";
    

    在任何地方设置值,其他页面都能访问

  3. 在其他界面读取数据

    NSString *name = [AppManager sharedManager].username;
    NSLog(@"读取到用户名:%@", name);
    
  4. 在整个运行周期存在,除非app关闭或者手动删除

    [AppManager sharedManager].username = nil;
    

总结

多界面传值是UI中相当重要且常见的一个知识点,要根据具体情况进行方法的选择,有时甚至需要结合起来使用,比如通知与单例结合起来使用等 ,多加使用,才能更熟练

你可能感兴趣的:(ios,cocoa,macos)