Coordinator 是 SwiftUI 中 UIViewRepresentable(iOS)或 NSViewRepresentable(macOS)协议的一部分,用来桥接 SwiftUI 与 UIKit/AppKit 控件之间的事件回调。
核心作用:让传统控件(如 NSColorWell、NSSlider、UIButton)能通过 target-action 或 delegate,把事件传回 SwiftUI 的状态或逻辑中。
为什么需要Coordinator?
UIKit/AppKit 控件通常是这样响应用户操作的:
button.target = someObject
button.action = #selector(someMethod(_:))
但 SwiftUI 是声明式的,没有 target-action 概念,为了让两者交互,SwiftUI 提供了 Coordinator。
Coordinator 的标准使用场景
以NSViewRepresentable为例,在SwiftUI中实现AppKit控件时,需要实现makeNSView和updateNSView方法。
比如,在SwiftUI中实现NSSlider:
struct NSSomeView: NSViewRepresentable {
func makeNSView(context: Context) -> NSSlider {
let slider = NSSlider()
slider.doubleValue = 50
slider.minValue = 0
slider.maxValue = 100
return slider
}
func updateNSView(_ nsView: NSSlider, context: Context) {
}
}
在SwiftUI中可以通过NSSomeView()显示对应的NS控件。

但是如果想要通过回调获取到控件的值,就需要使用Coordinator:
func makeCoordinator() -> Coordinator
然后在里面定义事件处理逻辑,如果不使用Coordinator,就无法获取到NS控件值。
Coordinator使用实例
以使用场景中的NSSlider为例,如果想要获取到NSSlider的值,就需要绑定一个变量,并通过Coordinator实现值的回调:
struct MySlider: NSViewRepresentable {
@Binding var value: Double
func makeNSView(context: Context) -> NSSlider {
let slider = NSSlider(value: value, minValue: 0, maxValue: 100,
target: context.coordinator,
action: #selector(Coordinator.valueChanged(_:)))
return slider
}
func updateNSView(_ nsView: NSSlider, context: Context) {
if nsView.doubleValue != value {
nsView.doubleValue = value
}
}
func makeCoordinator() -> Coordinator {
Coordinator(value: $value)
}
class Coordinator: NSObject {
var value: Binding<Double>
init(value: Binding<Double>) {
self.value = value
}
@objc func valueChanged(_ sender: NSSlider) {
value.wrappedValue = sender.doubleValue
print("值改变为:\(value.wrappedValue)")
}
}
}
在SwiftUI中,通过 @Binding 实现数据的传输绑定:
struct ContentView: View {
@State private var value: Double = 50
var body: some View {
VStack {
Text("进度:") + Text(String(format: "%.f",value)) + Text("%")
MySlider(value: $value)
.frame(width: 100,height:35)
}
.frame(width: 400,height:300)
}
}

代码详解
1、结构体和 @Binding 变量
struct MySlider: NSViewRepresentable {
@Binding var value: Double
首先,创建一个遵循NSViewRepresentable结构体,用于显示NS控件。
创建一个 @Binding 的变量,用于接收从 SwiftUI 父视图传递的数值,当用户滑动滑块时,将更新的值传回SwiftUI的变量。
2、makeNSView
func makeNSView(context: Context) -> NSSlider
这是SwiftUI创建NSSlider时,第一次调用的函数。
let slider = NSSlider(
value: value, // 初始值(来自 @Binding)
minValue: 0,
maxValue: 100,
target: context.coordinator, // 设置 target 为协调器
action: #selector(Coordinator.valueChanged(_:))
)
创建了一个NSSlider控件,并设置初始化、最小值、最大值、target和action。
当用户滑动滑块时,会调用Coordinator的valueChanged方法。
3、updateNSView
func updateNSView(_ nsView: NSSlider, context: Context)
这是 SwiftUI 检测到 @State 或 @Binding 变化后会自动调用的更新函数,用来同步最新值到 NSSlider:
if nsView.doubleValue != value {
nsView.doubleValue = value
}
如果隐藏updateNSView内部的代码,NSSlider控件仍然可以实现数据的回调,但是无法从SwiftUI状态同步到AppKit视图。
例如,在SwiftUI中创建一个生成随机数的按钮:
Button("修改随机值") {
value = Double(Int.random(in: 0...100))
}
当点击该按钮时,外部的 @State 值就会改变,NSSlider控件就会通过 @Binding 检测到外部值发生了变化,SwiftUI自动调用updateNSView方法,将 NSSlider 的值同步到最新状态。
4、makeCoordinator
func makeCoordinator() -> Coordinator
SwiftUI 在构造视图时调用这个方法,用于创建一个事件回调桥梁对象。
自定义了一个 Coordinator 类:
Coordinator(value: $value)
把 @Binding 传进去,之后可以在 AppKit 控件里使用。
这里实际上是将 NSSlider 控件的变量传递到Coordinator类中,如果不实现Coordinator类,NSSlider控件的变量就无法传递给Coordinator类。
5、Coordinator(协调器)
class Coordinator: NSObject {
var value: Binding<Double>
init(value: Binding<Double>) {
self.value = value
}
@objc func valueChanged(_ sender: NSSlider) {
value.wrappedValue = sender.doubleValue
print("值改变为:\(value.wrappedValue)")
}
}
value: Binding<Double> 是通过makeCoordinator方法传递进来的,绑定的是 NSSlider 的 @Bindg变量,实际上用来回写 SwiftUI @State。
@objc func valueChanged 是 NSSlider 用户操作时调用的事件方法。
在这个方法中将 NSSlider滑块的值写回 @Binding。
Coordinator交互控件
1、NSColorWell:颜色变化回调传回 SwiftUI。
2、NSSlider:滑动数值更新 SwiftUI 的 @State。
3、NSTextField:编辑完成后更新 SwiftUI 的绑定。
4、NSView(自定义):手势、拖拽、鼠标事件等处理。
凡是需要数据回调的控件都需要用到Coordinator,只有展示或不需要交互的情况下,Coordinator才是可选的。
当需要 target-action、delegate、通知、代理等,就建议用 Coordinator。
Coordinator命名约定
如果在 NSViewRepresentable 中定义了一个类名叫做 Coordinator,SwiftUI 会强制要求实现 makeCoordinator() 方法。
struct MySlider: NSViewRepresentable { // 报错
// func makeCoordinator() -> Coordinator { } // 没有实现 makeCoordinator
class Coordinator: NSObject { } // 名称为 Coordinator
}

如果将这个类命名为别的名字(如 SliderDelegate 或 SomeHelper),SwiftUI 就不会强制实现 makeCoordinator(),因为它“不知道”是否需要使用协调器。
struct MySlider: NSViewRepresentable {
// func makeCoordinator() -> Coordinator { } // 不报错
class SliderDelegate: NSObject { } // 其他名称
}
这里的命名约定是因为,SwiftUI 的 NSViewRepresentable 协议有个默认行为:
associatedtype Coordinator = Void
也就是说,如果不实现 makeCoordinator() 方法,它假设不需要协调器,就用默认的 Void。
但当声明了一个嵌套类型 Coordinator,SwiftUI 就会:
1、自动把写的 Coordinator 类识别为“协调器类型”,
2、要求实现:
func makeCoordinator() -> Coordinator
所以出现了这种“写了类就必须实现方法”的行为 —— 是协议和默认泛型的联动机制。
总结
Coordinator是连接 SwiftUI 和 AppKit 的桥梁,通过实现 makeCoordinator() 方法,返回自定义类实例。
主要用于控件的事件处理、状态同步、手势监听等
相关文章
1、SwiftUI显示AppKit视图的NSViewRepresentable协议:https://fangjunyu.com/2025/07/02/swiftui%e6%98%be%e7%a4%baappkit%e8%a7%86%e5%9b%be%e7%9a%84nsviewrepresentable%e5%8d%8f%e8%ae%ae/
2、Swift科普文《associatedtype》:https://fangjunyu.com/2024/10/21/swift%e7%a7%91%e6%99%ae%e6%96%87%e3%80%8aassociatedtype%e3%80%8b/