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

macOS插入外接显示器后NSScreen显示器计数不更新问题

问题原因
  • NSScreen属于AppKit框架的上层接口,它的屏幕列表缓存更新依赖NSApplication实例的正常运行以及主RunLoop的事件分发:系统的显示器配置变更事件会通过NSApplicationDidChangeScreenParametersNotification通知给应用,AppKit收到通知后才会刷新[NSScreen screens]的返回值。你当前的程序是普通命令行程序,没有初始化NSApplication,也没有启动主RunLoop,AppKit没有运行环境接收系统事件,自然不会更新缓存。
  • 代码使用了无限死循环,即便初始化了NSApplication,死循环也会完全阻塞主RunLoop,事件无法分发,缓存依旧无法更新。
  • 而CGGetOnlineDisplayList是CoreGraphics的底层接口,每次调用都会直接从内核查询最新的显示器状态,不依赖AppKit的事件机制,所以可以实时返回正确数值。
解决方法

方案1:适配AppKit运行规则(推荐)

  1. 初始化NSApplication实例:在main函数入口最前面添加[NSApplication sharedApplication];,启动AppKit运行环境。
  2. 替换无限死循环为定时任务,让出RunLoop运行时间。可以用GCD的定时源实现,示例如下:
// 修正后的getNSScreenCoordinates实现
float getNSScreenCoordinates() {
    #define MAX_NUM_DISPLAYS 255
    // 每500ms执行一次打印
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        NSArray<NSScreen *> *arr = [NSScreen screens];
        NSUInteger numScreens = [arr count];

        CGDirectDisplayID displays[MAX_NUM_DISPLAYS];
        CGDisplayCount displayCount;
        CGGetOnlineDisplayList(MAX_NUM_DISPLAYS, displays, &displayCount);
        
        std::cout << "cg num displays " << displayCount << "\n";
        std::cout << "numscreens " << numScreens << "\n";
    });
    dispatch_resume(timer);
    
    // 启动主RunLoop保证程序不退出
    [[NSRunLoop mainRunLoop] run];
    return 1;
}

方案2:监听显示器变更通知(更高效)

不需要轮询,直接监听系统的显示器配置变更通知,收到通知后再获取最新的屏幕列表:

float getNSScreenCoordinates() {
    #define MAX_NUM_DISPLAYS 255
    [NSApplication sharedApplication];
    // 监听显示器变更通知
    [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidChangeScreenParametersNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
        NSArray<NSScreen *> *arr = [NSScreen screens];
        NSUInteger numScreens = [arr count];

        CGDirectDisplayID displays[MAX_NUM_DISPLAYS];
        CGDisplayCount displayCount;
        CGGetOnlineDisplayList(MAX_NUM_DISPLAYS, displays, &displayCount);
        
        std::cout << "=== 显示器配置变更 ===" << "\n";
        std::cout << "cg num displays " << displayCount << "\n";
        std::cout << "numscreens " << numScreens << "\n";
    }];
    
    [[NSRunLoop mainRunLoop] run];
    return 1;
}

内容的提问来源于stack exchange,提问作者Pradeep Chakravarti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 23:24:03