You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Objective-C:VC/类初始化方法及NSNotificationCenter传参问题咨询

Objective-C开发问题解答:VC初始化与通知中心适配

嘿,我来帮你解决这两个iOS Objective-C开发里的常见问题😉


一、如何在Objective-C环境下初始化视图控制器(VC)或类?

1. 普通类的初始化方式

  • 无参基础初始化:对于不需要初始参数的类,直接用最经典的alloc + init组合:
    YourCustomClass *instance = [[YourCustomClass alloc] init];
    
  • 自定义带参初始化:如果类需要在创建时就传入配置信息,可以自定义初始化方法,比如:
    // 在YourCustomClass.h中声明
    - (instancetype)initWithTitle:(NSString *)title content:(NSString *)content;
    
    // 在YourCustomClass.m中实现
    - (instancetype)initWithTitle:(NSString *)title content:(NSString *)content {
        self = [super init];
        if (self) {
            self.title = title;
            self.content = content;
        }
        return self;
    }
    
    // 调用初始化
    YourCustomClass *instance = [[YourCustomClass alloc] initWithTitle:@"测试标题" content:@"测试内容"];
    

2. 视图控制器(VC)的初始化方式

VC的初始化分纯代码、XIB、Storyboard三种场景:

  • 纯代码VC初始化:直接调用init即可,若需要指定自定义初始化逻辑,重写init方法:
    FirstVC *firstVC = [[FirstVC alloc] init];
    
  • XIB关联的VC初始化:如果VC是用XIB文件创建的,用initWithNibName:bundle:指定XIB名称:
    SecondVC *secondVC = [[SecondVC alloc] initWithNibName:@"SecondVC" bundle:nil];
    
  • Storyboard中的VC初始化:先获取对应Storyboard实例,再通过Storyboard ID实例化VC(注意要在Storyboard里给VC设置好Storyboard ID):
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    SecondVC *secondVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"SecondVCID"];
    

二、NSNotificationCenter通知无法传递的问题解决

首先拆解你的问题:首次启动时SecondVC还没被初始化,自然没注册通知监听,所以收不到FirstVC发的通知。至于要不要在- (BOOL)application:didFinishLaunchingWithOptions:里初始化SecondVC?我非常不推荐这么做,因为这会提前把SecondVC加载进内存,平白增加启动时的内存开销,拖慢App启动速度,除非你的业务场景真的需要它在后台静默存在(这种情况极少)。

下面给你几个更合理的解决方案:

方案1:缓存数据 + 延迟处理

当FirstVC点击按钮时,先判断SecondVC是否已经存在于视图层级中:

  • 如果存在:直接发送通知;
  • 如果不存在:先缓存数据,等SecondVC初始化完成后,主动读取缓存数据处理。

示例代码:

// FirstVC中按钮点击事件
- (IBAction)triggerSecondVCAction:(UIButton *)sender {
    NSDictionary *transferData = @{@"userId": @"123", @"userName": @"Hanz"};
    
    // 检查SecondVC是否在导航栈中
    BOOL isSecondVCExist = NO;
    for (UIViewController *vc in self.navigationController.viewControllers) {
        if ([vc isKindOfClass:[SecondVC class]]) {
            isSecondVCExist = YES;
            break;
        }
    }
    
    if (isSecondVCExist) {
        // 直接发送通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"UserInfoUpdate" 
                                                            object:nil 
                                                          userInfo:transferData];
    } else {
        // 缓存数据到AppDelegate(也可以用单例类管理,更优雅)
        AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
        appDelegate.cachedUserInfo = transferData;
        
        // 直接跳转到SecondVC
        SecondVC *secondVC = [[SecondVC alloc] init];
        [self.navigationController pushViewController:secondVC animated:YES];
    }
}

// SecondVC的viewDidLoad方法
- (void)viewDidLoad {
    [super viewDidLoad];
    // 注册通知监听
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(handleUserInfoUpdate:) 
                                                 name:@"UserInfoUpdate" 
                                               object:nil];
    
    // 检查缓存数据并处理
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    if (appDelegate.cachedUserInfo) {
        [self handleUserInfoUpdate:nil];
        // 处理完清空缓存
        appDelegate.cachedUserInfo = nil;
    }
}

// 通知处理方法
- (void)handleUserInfoUpdate:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo ?: ((AppDelegate *)[UIApplication sharedApplication].delegate).cachedUserInfo;
    // 这里写你的数据处理逻辑,比如更新UI
    NSLog(@"收到数据:%@", userInfo);
}

// 记得在dealloc中移除监听,避免野指针
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

方案2:直接给VC传参(更简洁)

如果你的需求是点击按钮后跳转到SecondVC并传递数据,完全可以不用通知中心,直接给SecondVC的属性赋值:

// FirstVC按钮点击事件
- (IBAction)goToSecondVCAction:(UIButton *)sender {
    NSDictionary *transferData = @{@"userId": @"123", @"userName": @"Hanz"};
    SecondVC *secondVC = [[SecondVC alloc] init];
    // 直接给VC的属性赋值
    secondVC.passedUserInfo = transferData;
    [self.navigationController pushViewController:secondVC animated:YES];
}

// SecondVC.h中声明属性
@property (nonatomic, strong) NSDictionary *passedUserInfo;

// SecondVC的viewDidLoad中处理数据
- (void)viewDidLoad {
    [super viewDidLoad];
    if (self.passedUserInfo) {
        NSLog(@"直接收到数据:%@", self.passedUserInfo);
        // 处理数据逻辑
    }
}

这种方式比通知中心更直接,耦合性也更低,适合页面跳转时的数据传递场景。

方案3:单例类统一管理数据

如果你的数据需要在多个VC之间共享,可以创建一个单例的DataManager类,用来存储和获取数据:

// DataManager.h
@interface DataManager : NSObject
@property (nonatomic, strong) NSDictionary *sharedUserInfo;
+ (instancetype)sharedManager;
@end

// DataManager.m
@implementation DataManager
+ (instancetype)sharedManager {
    static DataManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[DataManager alloc] init];
    });
    return manager;
}
@end

// FirstVC中存储数据
- (IBAction)sendDataAction:(UIButton *)sender {
    [[DataManager sharedManager] setSharedUserInfo:@{@"userId": @"123"}];
    // 跳转到SecondVC
    SecondVC *secondVC = [[SecondVC alloc] init];
    [self.navigationController pushViewController:secondVC animated:YES];
}

// SecondVC中读取数据
- (void)viewDidLoad {
    [super viewDidLoad];
    NSDictionary *userInfo = [[DataManager sharedManager] sharedUserInfo];
    if (userInfo) {
        // 处理数据
    }
}

内容的提问来源于stack exchange,提问作者Hanz Cheah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:42:10