@SceneBuilder 是 SwiftUI 中的一个属性包装器,用于构建 App 入口的 Scene 列表。通常会在 SwiftUI App 的入口(符合 App 协议的 struct)中看到它,用来声明多个 Scene(窗口、菜单栏、文档等)。
例如,在SwiftUI中的body背后就是由 @SceneBuilder 包装器支持的。
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
基本定义
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, visionOS 1.0, *)
@resultBuilder public struct SceneBuilder {
// 实现了构建多个 Scene 的方法
}
@SceneBuilder 是一个 Result Builder(结果构建器),允许像写 DSL(领域特定语言)一样写多个 Scene。
代码示例
例如,在使用MenuBarExtra状态栏时,可以将MenuBarExtra使用 @SceneBuilder 封装成Scene:
@main
struct ImageSlimApp: App {
@SceneBuilder
var menuBarExtraScene: some Scene {
if #available(macOS 13.0, *) {
MenuBarExtra("我的图标", systemImage: "gearshape") {
Button("执行操作") {
print("点击了菜单项")
}
Divider()
Button("退出") {
NSApp.terminate(nil)
}
}
}
}
var body: some Scene {
menuBarExtraScene
WindowGroup {
ContentView()
}
}
}
在这个代码中 @SceneBuilder 是一个结果构建器(Result Builder),用于构建多个 Scene(即多个窗口或菜单栏等界面容器)。它的作用是在 menuBarExtraScene 中像写 DSL 一样用 if 条件语句、多个 Scene 并列声明等方式灵活构建内容。
@SceneBuilder
var menuBarExtraScene: some Scene {
if #available(macOS 13.0, *) {
MenuBarExtra("我的图标", systemImage: "gearshape") {
Button("执行操作") {
print("点击了菜单项")
}
Divider()
Button("退出") {
NSApp.terminate(nil)
}
}
}
}
@SceneBuilder 是一个 SwiftUI 提供的构建器属性(Attribute),用于组装多个 Scene。
如果不用 @SceneBuilder,则无法直接在 var 中写 if 和多个 Scene 返回值的,编译器会报错。

报错信息:
Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
// 函数声明了一个不透明的返回类型,但其主体中没有返回语句来推断底层类型
因此,@SceneBuilder 的作用就是让这种 DSL 式的写法合法并且有语义。
最后,在var body中的两个Scene:
一个是 macOS 13+ 的菜单栏图标(MenuBarExtra)。
一个是常规窗口 WindowGroup。
和其他 builder 的类相比
1、构建View:使用@ViewBuilder。
var body: some View { ... }
2、构建Scene:使用@SceneBuilder。
var body: some Scene { ... }
3、构建 Commands:使用@CommandsBuilder。
var commands: some Commands
4、构建 ToolbarContent:使用@ToolbarContentBuilder。
总结
@SceneBuilder 是 SwiftUI 用来构建多个 Scene(如窗口、菜单栏、设置窗口)的结果构建器,它能像写多段 View 一样,声明多个 Scene,常见于 App 协议中。
相关文章
macOS状态栏MenuBarExtra:https://fangjunyu.com/2025/06/29/macos%e7%8a%b6%e6%80%81%e6%a0%8fmenubarextra/