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

iOS:如何检测后台运行的另一ViewController中变量值的变化

嘿,我来帮你梳理下当前的问题和可行的解决方案~

首先得指出你目前代码里的两个核心问题:

  1. 阻塞主线程:你在FormViewController里用[NSThread sleepForTimeInterval:1.0]加循环等待的方式,会直接卡死主线程——不仅用户界面完全无响应,甚至可能触发系统的Watchdog机制杀死APP。更糟的是,主线程被阻塞后,ViewController里设置isSyncAutoOnGoing = NO的主线程代码也没法执行,所以你才会一直看到YES的结果。
  2. 实例变量访问不规范:isSyncAutoOnGoing是ViewController的私有实例变量,用valueForKey:访问属于非常规操作,不仅不安全,还可能因为KVC的规则导致获取不到正确的值。

下面是几种推荐的正确实现思路,按场景优先级排序:


方法一:NSNotificationCenter(通知中心)——最省心的跨页面通信

这是iOS里最常用的跨组件状态通知方式,适合不需要强耦合的场景。

步骤1:在ViewController里发送完成通知

当下载完成、设置isSyncAutoOnGoing = NO后,发送一个全局通知:

// 在主线程的代码块中,设置完isSyncAutoOnGoing=NO后添加
[[NSNotificationCenter defaultCenter] postNotificationName:@"SyncTaskCompleted" object:nil];

步骤2:在FormViewController里监听通知

在viewDidLoad中注册监听,实现回调方法:

- (void)viewDidLoad {
    [super viewDidLoad];
    // 注册通知监听
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(onSyncCompleted:) 
                                                 name:@"SyncTaskCompleted" 
                                               object:nil];
}

// 通知回调
- (void)onSyncCompleted:(NSNotification *)notification {
    NSLog(@"同步任务已完成,isSyncAutoOnGoing现在是NO");
    // 这里写你需要执行的后续逻辑
}

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

方法二:代理模式——适合明确的页面层级关系

如果FormViewController是从ViewController跳转过来的(比如push/present),用代理可以实现更严谨的耦合关系。

步骤1:定义代理协议

在ViewController的头文件里添加协议:

@protocol SyncStatusDelegate <NSObject>
- (void)syncTaskDidFinish;
@end

@interface ViewController : UIViewController
@property (nonatomic, weak) id<SyncStatusDelegate> syncDelegate;
// 把原来的实例变量改成@property,规范访问
@property (nonatomic, assign) BOOL isSyncAutoOnGoing;
@end

步骤2:ViewController里调用代理方法

下载完成时触发代理回调:

// 主线程代码块中,设置完isSyncAutoOnGoing=NO后
if ([self.syncDelegate respondsToSelector:@selector(syncTaskDidFinish)]) {
    [self.syncDelegate syncTaskDidFinish];
}

步骤3:FormViewController实现代理

// FormViewController.h
#import "ViewController.h"
@interface FormViewController : UIViewController <SyncStatusDelegate>
@end

// FormViewController.m
- (void)viewDidLoad {
    [super viewDidLoad];
    // 找到对应的ViewController实例,设置代理
    NSArray *viewControllers = [[self navigationController] viewControllers];
    for (id obj in viewControllers) {
        if ([obj isKindOfClass:[ViewController class]]) {
            ((ViewController *)obj).syncDelegate = self;
            break;
        }
    }
}

- (void)syncTaskDidFinish {
    NSLog(@"同步完成,isSyncAutoOnGoing变为NO");
    // 执行你的后续逻辑
}

方法三:KVO(键值观察)——实时监听属性变化

如果需要实时追踪isSyncAutoOnGoing的每一次变化,KVO是合适的选择。

步骤1:将isSyncAutoOnGoing改为@property

首先在ViewController里把实例变量改成属性:

@interface ViewController ()
@property (nonatomic, assign) BOOL isSyncAutoOnGoing;
@end

步骤2:FormViewController添加观察者

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *viewControllers = [[self navigationController] viewControllers];
    for (id obj in viewControllers) {
        if ([obj isKindOfClass:[ViewController class]]) {
            [obj addObserver:self 
                  forKeyPath:@"isSyncAutoOnGoing" 
                     options:NSKeyValueObservingOptionNew 
                     context:nil];
            break;
        }
    }
}

// KVO回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                       context:(void *)context {
    if ([keyPath isEqualToString:@"isSyncAutoOnGoing"]) {
        BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
        if (!newValue) {
            NSLog(@"isSyncAutoOnGoing已变为NO,同步完成");
            // 执行后续逻辑
        }
    }
}

// 销毁时移除观察者
- (void)dealloc {
    NSArray *viewControllers = [[self navigationController] viewControllers];
    for (id obj in viewControllers) {
        if ([obj isKindOfClass:[ViewController class]]) {
            [obj removeObserver:self forKeyPath:@"isSyncAutoOnGoing"];
            break;
        }
    }
}

方法四:单例管理全局状态——适合多页面关注同步状态

如果你的APP里有多个页面需要关注同步任务的状态,可以把状态放到单例类中统一管理。

步骤1:创建SyncManager单例

// SyncManager.h
@interface SyncManager : NSObject
@property (nonatomic, assign) BOOL isSyncAutoOnGoing;
+ (instancetype)sharedManager;
@end

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

步骤2:ViewController中使用单例状态

- (void)sync:(id)sender {
    [[SyncManager sharedManager] setIsSyncAutoOnGoing:YES];
    dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
    dispatch_async(downloadQueue, ^{
        // 耗时下载任务
        ListOfValueSync *lovSync = [[ListOfValueSync alloc] init];
        BOOL ret = [lovSync getAllListOfValueAll];
        dispatch_async(dispatch_get_main_queue(), ^{
            [spinner stopAnimating];
            [spinner removeFromSuperview];
            [[SyncManager sharedManager] setIsSyncAutoOnGoing:NO];
            // 其他原有代码...
        });
    });
}

步骤3:FormViewController监听单例状态

可以用通知、KVO或者直接读取单例属性,这里以KVO为例:

- (void)viewDidLoad {
    [super viewDidLoad];
    [[SyncManager sharedManager] addObserver:self 
                                  forKeyPath:@"isSyncAutoOnGoing" 
                                     options:NSKeyValueObservingOptionNew 
                                     context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                       context:(void *)context {
    if ([keyPath isEqualToString:@"isSyncAutoOnGoing"]) {
        BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
        if (!newValue) {
            NSLog(@"全局同步任务已完成");
        }
    }
}

- (void)dealloc {
    [[SyncManager sharedManager] removeObserver:self forKeyPath:@"isSyncAutoOnGoing"];
}

总结一下:

  • 优先选择通知中心,实现简单且耦合度低;
  • 如果页面层级明确,用代理模式更严谨;
  • 需要实时追踪属性变化选KVO;
  • 多页面关注状态用单例管理。

绝对要避免阻塞主线程的循环等待方式,这是iOS开发的大忌哦~

内容的提问来源于stack exchange,提问作者ΩlostA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:25:43