内置大量CALayer的层托管NSView(WindowServer - CPU 100%)

时间:2017-09-12 12:04:34

标签: performance cocoa calayer cpu-usage nsview

我有一个有趣的案例。需要帮助。

我的Mac应用程序有一个图层托管的NSView,其中包含许多图层和子图层以及子图层。想象一个带有项目(图标,文本标签)的Finder窗口......就像那样。每个项目都有一个按钮,选择背景图层。

一切都很好,直到你有1000件物品。

现在有很多这些项目,当我尝试与此视图进行交互时,我的应用程序变得没有响应。而棘手的部分是它不是我的应用程序消耗CPU,而是WindowServer。它达到100%并且系统冻结了一段时间。

重要提示:

我的观点是应用界面的一部分。有一个主窗口,其他视图。它们也有自己的结构。

我注意到如果我把这个图层托管的视图放到一个单独的窗口中,它可以正常工作,没有冻结具有相同的1000个项目。但是如果我把它放回主窗口就开始停止系统。

问题

  1. 我的应用程序(视图/图层)是什么让WindowServer变得疯狂?
  2. 为什么将此视图放到单独的窗口有帮助?
  3. 我已经进行了一些测试并删除了每个项目的所有子图层,每个项目只留下一两个。它减轻了系统的负担,但仍然很糟糕。我已经禁用了所有图纸 - 只是图标的小图像。没有帮助。

2 个答案:

答案 0 :(得分:3)

WindowServer的主要工作是为macOS绘制与图形相关的内容,这意味着您可以在整个屏幕上看到所有内容,您必须通过WindowServer并让它为您绘制。< / p>

WindowServer使用高CPU的原因有很多。

  1. 您的应用程序中有复杂的绘图方法。 - 尝试简化您的绘图方法。
  2. 桌面上有很多图形,因此WindowServer不仅可以绘制应用程序,还可以绘制桌面图形。 - 尝试清理桌面。
  3. 您打开了一些需要复杂图形绘制的应用程序? - 尝试关闭该应用程序。
  4. 在看到您的确切代码之前,我无法告诉您为什么将元素放入单独的窗口可以提供帮助。也许窗口本身隐藏了一些东西,以便更容易绘制?

    我的一个软件有很多图形元素和动画。但我从未遇到过你的问题。如何创建测试项目并尝试类似的东西?有时,它可能有助于在更清晰的项目结构上看到问题。

    我创建了一个简单的演示,窗口中有100 * 100个子图层。这似乎没什么问题。

    import Cocoa
    
    @NSApplicationMain
    class AppDelegate: NSObject, NSApplicationDelegate {
    
    @IBOutlet weak var window: NSWindow!
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
        self.window.contentView?.wantsLayer = true
    
        let size = 10
        for i in 0..<10000 {
            let x = i%100
            let y = i/100
    
            let layer = CALayer()
            layer.frame = NSRect(x: x*size, y: y*size, width: size, height: size)
            layer.backgroundColor = .random()
            self.window.contentView?.layer?.addSublayer(layer)
        }
    
    }
    
    
    
       func applicationWillTerminate(_ aNotification: Notification) {
            // Insert code here to tear down your application
        }
    }
    
    extension CGFloat {
        static func random() -> CGFloat {
            return CGFloat(arc4random()) / CGFloat(UInt32.max)
        }
    }
    
    extension CGColor {
        static func random() -> CGColor {
            return CGColor(red:   .random(),
                           green: .random(),
                           blue:  .random(),
                           alpha: 1.0)
        }
    }
    

    enter image description here

答案 1 :(得分:0)

我刚刚发现,如果窗户没有边框,你就会遇到麻烦。但是使styleMask NSWindowStyleMaskTitled完全解决了这个问题。

似乎无边框窗口的处理方式不同。

现在我需要找到隐藏所有标题栏控件的方法,保留掩码。我已经这样做了:

  • NSFullSizeContentViewWindowMask添加到窗口掩码
  • 加入

    self.titlebarAppearsTransparent = YES;
    self.titleVisibility = NSWindowTitleHidden;
    

但是窗口仍然显示左上方的3个按钮。

任何想法如何隐藏它们?