UI----多界面传值

UI多界面传值

文章目录

在iOS开发过程中,多界面之间的传值时最核心、最常用的需求,因此我们需要掌握一些多界面传值的方法,本篇博客将介绍5种方法供以参考学习

一、属性传值

这是iOS最基础与常用的传值方式

  1. 原理:在目标界面(B 界面)的 .h 文件中声明公开属性,当前界面(A 界面)跳转时,创建 B 界面的实例对象,直接给其公开属性赋值,赋值完成后再执行跳转操作,B 界面即可在自身代码中使用该属性值。
  2. 适用场景:用于正向传值
  3. 代码演示:
objc 复制代码
// BViewController.h
#import <UIKit/UIKit.h>

@interface BViewController : UIViewController

// 声明需要接收的属性(公开属性,供A界面赋值)
@property (nonatomic, copy) NSString *goodsName;
@property (nonatomic, assign) NSInteger goodsId;
@property (nonatomic, strong) NSDictionary *userInfo;

@end
objc 复制代码
// AViewController.m
#import "AViewController.h"
#import "BViewController.h"

@interface AViewController ()
// 可声明A界面自身的属性(如模拟数据)
@property (nonatomic, copy) NSString *aName;
@property (nonatomic, assign) NSInteger aId;
@property (nonatomic, strong) NSDictionary *aUserInfo;
@end

@implementation AViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 模拟A界面的初始数据(实际开发中可能是接口请求、用户输入的数据)
    self.aName = @"iPhone 15 Pro";
    self.aId = 10001;
    self.aUserInfo = @{@"userName": @"OC开发者", @"age": @25};
    self.title = @"A界面(传值方)";
    UIButton *jumpBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    jumpBtn.frame = CGRectMake(100, 200, 200, 50);
    [jumpBtn setTitle:@"跳转至B界面" forState:UIControlStateNormal];
    [jumpBtn addTarget:self action:@selector(jumpToBViewController) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:jumpBtn];
}

// 跳转按钮点击事件:跳转至B界面,并传值
- (void)jumpToBViewController {
    BViewController *bVC = [[BViewController alloc] init];
    // 2. 给B界面的公开属性赋值(核心步骤)
    bVC.goodsName = self.aName;  
    bVC.goodsId = self.aId;   
    bVC.userInfo = self.aUserInfo;    
    [self.navigationController pushViewController:bVC animated:YES];
}

@end
objc 复制代码
// BViewController.m
#import "BViewController.h"

@implementation BViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"B界面(接收方)";
    self.view.backgroundColor = [UIColor whiteColor];
    
    // 接收并使用A界面传递过来的值(直接访问自身属性即可)
    NSLog(@"接收的商品名称:%@", self.goodsName);
    NSLog(@"接收的商品ID:%ld", self.goodsId);
    NSLog(@"接收的用户信息:%@", self.userInfo);
    UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 150, 300, 30)];
    nameLabel.text = [NSString stringWithFormat:@"商品名称:%@", self.goodsName];
    [self.view addSubview:nameLabel];
    
    UILabel *idLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 200, 300, 30)];
    idLabel.text = [NSString stringWithFormat:@"商品ID:%ld", self.goodsId];
    [self.view addSubview:idLabel];
    
    UILabel *userLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 250, 300, 30)];
    userLabel.text = [NSString stringWithFormat:@"用户信息:%@", self.userInfo[@"userName"]];
    [self.view addSubview:userLabel];
}

@end
  1. 缺点:

    • 仅支持正向传值(A→B),无法反向传值;

    • 多层级传值繁琐,需层层中转;

    • 无法实现全局共享,仅能在两个有跳转关系的界面之间传递。

二、代理传值

  1. 原理:通过"协议"定义传值方法,目标界面(B 界面)声明一个代理属性(遵循该协议),当前界面(A 界面)遵守该协议并实现协议中的传值方法,同时将 B 界面的代理设置为 A 自身。当 B 界面需要回传数据时,调用代理的传值方法,将数据作为参数传递,A 界面通过实现的方法接收数据。

  2. 适用场景:反向传值

  3. 核心要素:

    1. 定义协议:

      objc 复制代码
      @protocol BViewControllerDelegate <NSObject>
      - (void)didPassData:(NSString *)data; // 传值方法
      @end
    2. 声明弱引用代理属性

      objc 复制代码
      @interface BViewController : UIViewController
      @property (nonatomic, weak) id<BViewControllerDelegate> delegate;
      @end
    3. 设置代理

      objc 复制代码
      BViewController *bVC = [[BViewController alloc] init];
      bVC.delegate = self; // 关键:指定代理为当前 VC
      [self.navigationController pushViewController:bVC animated:YES];
    4. 安全调用代理方法

      objc 复制代码
      if ([self.delegate respondsToSelector:@selector(didPassData:)]) {
          [self.delegate didPassData:@"要传的值"]; // 回传数据
      }
    5. 遵守协议并实现方法

      objc 复制代码
      // AViewController.h
      @interface AViewController : UIViewController <BViewControllerDelegate>
      
      // AViewController.m
      - (void)didPassData:(NSString *)data {
          NSLog(@"收到值:%@", data); // 接收并使用数据
      }

三、Block传值

  1. 原理:在目标界面(B 界面)的 .h 文件中定义一个 Block 类型(Block 的参数即为需要回传的数据类型),并声明一个 Block 属性;当前界面(A 界面)跳转时,给 B 界面的 Block 属性赋值(实现 Block 的具体逻辑);当 B 界面需要回传数据时,调用该 Block,将数据作为参数传入,A 界面通过 Block 的实现逻辑接收数据。
  2. 适用场景:反向传值
  3. 代码演示:
objc 复制代码
//FirstViewController.m

#import "FirstViewController.h"
#import "SecondViewController.h"
@interface FirstViewController ()

@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"首页";
    // 按钮:跳转到第二个界面
    UIButton *btn = [UIButton buttonWithType:(UIButtonTypeRoundedRect)];
    btn.frame = CGRectMake(150, 150, 150, 50);
    [btn setTitle:@"跳转到第二个界面" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(jumpClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
}
- (void)jumpClick {
    SecondViewController *secondVC = [[SecondViewController alloc] init];
    
    // Block 核心:接收第二个界面传回来的值
    secondVC.sendBackBlock= ^(NSString *text) {
    NSLog(@"首页收到回传:%@", text);
    
    // 这里可以更新 UI
        UILabel* lable = [[UILabel alloc] init];
        lable.text = text;
        lable.frame = CGRectMake(100, 300, 100, 100);
        [self.view addSubview:lable];
        
    };
    
    [self.navigationController pushViewController:secondVC animated:YES];
}

@end
objc 复制代码
//  SecondViewController.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SecondViewController : UIViewController
  //定义Block
@property(nonatomic,copy)void(^sendBackBlock)(NSString*text);
@end

NS_ASSUME_NONNULL_END
objc 复制代码
//  SecondViewController.m


#import "SecondViewController.h"

@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor greenColor];
    UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btn.frame = CGRectMake(100, 300, 150, 50);
    [btn setTitle:@"回传给上一个界面" forState:(UIControlStateNormal)];
    [btn addTarget:self action:@selector(sendvalueback) forControlEvents:(UIControlEventTouchUpInside)];
    [self.view addSubview:btn];
}

-(void)sendvalueback
{
    if(self.sendBackBlock){
        self.sendBackBlock(@"我是第二个界面回传的值");
    }
    [self.navigationController popViewControllerAnimated:YES];
}


@end

四、通知传值

  1. 原理:利用 NSNotificationCenter(通知中心),一个界面(发送者)发送通知,并携带需要传递的数据;多个界面(接收者)注册该通知,当通知发送后,所有注册了该通知的接收者都会收到通知,并获取携带的数据。

  2. 适用场景:一对多传值

  3. 关键语法

    objc 复制代码
    - (void)addObserver:(id)observer 
               selector:(SEL)aSelector 
                   name:(nullable NSString *)aName 
                 object:(nullable id)anObject;//添加观察者
    
    - (void)postNotificationName:(NSString *)aName 
                          object:(nullable id)anObject 
                        userInfo:(nullable NSDictionary *)aUserInfo;//发布通知
    
    - (void)removeObserver:(id)observer;//移处观察者
  4. 运用模版

    步骤 1:定义常量(用于防止写错名字)

    objc 复制代码
    // 推荐做法:定义常量
    #define kNotificationName_UserLogin @"UserLoginSuccessNotification"

    步骤 2:接收方 - 订阅

    objc 复制代码
    // 1. 在 viewDidLoad 注册
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(handleLogin:)
                                                     name:kNotificationName_UserLogin
                                                   object:nil]; // object 填 nil 表示接收所有发送者的通知
    }
    
    // 2. 接收消息的方法
    - (void)handleLogin:(NSNotification *)notification {
        // 3. 取出数据
        NSDictionary *info = notification.userInfo;
        NSString *token = info[@"token"];
        
        NSLog(@"登录成功,token 是:%@", token);
        
        // 4. 拿到数据后,做你想做的事(比如刷新 UI)
        [self refreshUIWithToken:token];
    }
    
    // 5. 离开时移除(必写)
    - (void)dealloc {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }

    步骤 3:发送方 - 发布

    objc 复制代码
    // 构造要传递的数据
    NSDictionary *userInfo = @{@"token": @"123456abcdef", @"userId": @"10086"};
    
    // 发送通知
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName_UserLogin
                                                        object:nil
                                                      userInfo:userInfo];

五、单例传值

  1. 原理:创建一个单例类(整个项目只有一个实例),在该类中声明共享属性;任何界面都能通过单例类的类方法获取实例,对共享属性进行存值、取值,实现多个界面的数据共享。

  2. 适用场景:全局共享数据

  3. 代码演示

    先创建单例类,数据存在这里可以在多个界面共享

    objc 复制代码
    //  SingletonManager.h
    
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface SingletonManager : NSObject
    + (instancetype)sharedManager;
    
    @property (nonatomic, copy) NSString *contentText;
    @end
    
    NS_ASSUME_NONNULL_END
    objc 复制代码
    //  SingletonManager.m
    
    #import "SingletonManager.h"
    
    @implementation SingletonManager
    + (instancetype)sharedManager {
        static SingletonManager *instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[super allocWithZone:NULL] init];
        });
        return instance;
    }
    
    // 防止外部手动 alloc 生成新实例
    + (instancetype)allocWithZone:(struct _NSZone *)zone {
        return [self sharedManager];
    }
    @end

    界面一,存值

    objc 复制代码
    //  ViewController.m
    
    
    #import "ViewController.h"
    #import "SecondViewController.h"
    #import "SingletonManager.h"
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.view.backgroundColor = [UIColor whiteColor];
        self.title = @"第一页:存数据";
    
        //  给单例存数据
        SingletonManager *manager = [SingletonManager sharedManager];
        manager.contentText = @"我是来自第一页的消息:单例传值成功啦!";
        
        // 打印验证
        NSLog(@"第一页存入:%@", manager.contentText);
        
        // 跳转到第二页的按钮
        UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(50, 200, 300, 60)];
        btn.backgroundColor = [UIColor blueColor];
        [btn setTitle:@"跳去第二页取数据" forState:UIControlStateNormal];
        [btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:btn];
    }
    - (void)jump {
        SecondViewController *vc2 = [[SecondViewController alloc] init];
        [self.navigationController pushViewController:vc2 animated:YES];
    }
    
    @end

    界面二取值

    objc 复制代码
    //  SecondViewController.m
    
    #import "SecondViewController.h"
    #import "SingletonManager.h"
    @interface SecondViewController ()
    
    @end
    
    @implementation SecondViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.view.backgroundColor = [UIColor whiteColor];
        self.title = @"第二页:取数据";
        
    
        // 从单例取数据(跨界面!)
        SingletonManager *manager = [SingletonManager sharedManager];
        NSString *result = manager.contentText;
            
        NSLog(@" 第二页取到:%@", result);
        
        // 显示在界面上
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(30, 200, 350, 100)];
        label.numberOfLines = 0;
        label.text = result;
        label.textColor = [UIColor redColor];
        [self.view addSubview:label];
    }
    
    @end
相关推荐
ZC跨境爬虫9 小时前
跟着 MDN 学CSS day_29:(掌握文本与字体样式的核心艺术)
前端·css·ui·html·tensorflow
帅次10 小时前
Android 17 开发者实战:核心更新与应用场景落地指南
android·java·ios·android studio·iphone·android jetpack·webview
人月神话Lee11 小时前
【图像处理】Core Image 与 GPU 渲染管线——让滤镜飞起来
ios·ai编程·图像识别
帅次18 小时前
讯飞与腾讯云:Android 实时语音识别服务对比选择
android·ios·微信小程序·小程序·android studio·android runtime
择势19 小时前
用一套View代码,同时支持RTL和LTR布局混合排版
ios
游戏开发爱好者820 小时前
iOS开发工具推荐:Xcode、AppCode、SwiftLint使用心得与效率提升
ide·vscode·macos·ios·个人开发·xcode·敏捷流程
UnicornDev21 小时前
【Flutter x HarmonyOS 6】设置页面的UI设计
flutter·ui·华为·harmonyos·鸿蒙
2501_9159090621 小时前
深入理解HTTPS中间人抓包技术原理与实战指南
网络协议·http·ios·小程序·https·uni-app·iphone
ZC跨境爬虫21 小时前
跟着 MDN 学CSS day_31:(精通链接样式,从伪类到导航菜单)
前端·javascript·css·ui·交互
lzp07911 天前
元数据驱动开发 - 面向对象编程思想的补充(上)
spring boot·后端·ui