Let's talk a little about a memory leak I recently found while working with UIViewRepresentable. The issue happened in a custom UIKit view wrapped inside SwiftUI. At first, nothing looked suspicious. The view worked fine. But after navigating in and out of the screen a few times, the Memory Graph Debugger showed that the Coordinator instances kept increasing. Here is a simplified version of the setup: import SwiftUI import UIKit final class CallbackButton: UIButton { var onTap: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) addTarget(self, action: #selector(handleTap), for: .touchUpInside) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func handleTap() { onTap?() } deinit { print("CallbackButton deinit") } } struct LeakyCallbackButtonView: UIViewRepresentable { @Binding var title: String func makeCoordinator() -> Coordinator { Coordinator(title: $title) } func makeUIView(context: Context) -> CallbackButton { let button = CallbackButton(type: .system) button.setTitle(title, for: .normal) // Looks harmless, but this strongly captures the coordinator. button.onTap = context.coordinator.handleTap return button } func updateUIView(_ uiView: CallbackButton, context: Context) { uiView.setTitle(title, for: .normal) } final class Coordinator { @Binding var title: String init(title: Binding<String>) { self._title = title print("Coordinator init") } func handleTap() { title = "Tapped at \(Date())" } deinit { print("Coordinator deinit") } } } The suspicious line is this one: button.onTap = context.coordinator.handleTap It looks like we are only passing a function, but an instance method reference still needs to retain its instance. In this case, the closure stored button.onTap strongly retains the Coordinator. In a normal UIKit view controller, many people would immediately fix this with [weak self]. But this is UIViewRepresentable. UIViewRepresentable is a struct, so self is a value type. You cannot use [weak self] the same way you would inside a UIViewController, because weak only applies to class-bound references. The fix is to weakly capture the Coordinator instead: struct FixedCallbackButtonView: UIViewRepresentable { @Binding var title: String func makeCoordinator() -> Coordinator { Coordinator(title: $title) } func makeUIView(context: Context) -> CallbackButton { let button = CallbackButton(type: .system) button.setTitle(title, for: .normal) button.onTap = { [weak coordinator = context.coordinator] in coordinator?.handleTap() } return button } func updateUIView(_ uiView: CallbackButton, context: Context) { uiView.setTitle(title, for: .normal) } static func dismantleUIView(_ uiView: CallbackButton, coordinator: Coordinator) { uiView.onTap = nil } final class Coordinator { @Binding var title: String init(title: Binding<String>) { self._title = title print("Coordinator init") } func handleTap() { title = "Tapped at \(Date())" } deinit { print("Coordinator deinit") } } } There are two fixes here: button.onTap = { [weak coordinator = context.coordinator] in coordinator?.handleTap() } This prevents the closure from strongly retaining the Coordinator. And: static func dismantleUIView(_ uiView: CallbackButton, coordinator: Coordinator) { uiView.onTap = nil } This clears the callback when SwiftUI dismantles the UIKit view. My takeaway: // UIKit / UIViewController { [weak self] in self?.doSomething() } // UIViewRepresentable { [weak coordinator = context.coordinator] in coordinator?.doSomething() } UIViewRepresentable is a value-type wrapper, but the Coordinator is the reference object that usually carries UIKit-style lifetime and callback behavior. So when a UIKit view stores a closure, be careful not to accidentally retain the Coordinator through that closure. Just a note for myself.