Skip to content

Instantly share code, notes, and snippets.

@atierian
Last active May 14, 2022
Embed
What would you like to do?
Allow consumers of SwiftUI UIViewRepresentable conforming Views to inject wrapped UIView delegate implementations through ViewModifiers using a ProxyDelegate.

Allow the consumer of a SwiftUI UIViewRepresentable View to inject delegate implementations for the wrapped UIView through View Modifiers by using a proxy delegate.

This can be a helpful pattern when providing a SwiftUI wrapper for a very heavy and complex UIView, where the wrapper implements many of the delegate methods of the wrapped UIView. But you want someone consuming the wrapper to have the ability to inject their own delegate method implementations to override yours, or to leverage some of the methods your not implementing.

import UIKit
import SwiftUI
protocol HeavyUIViewDelegate: AnyObject {
func heavyView(_ view: HeavyUIView, to thing: Int)
func heavyView(_ view: HeavyUIView, titleForThing: String) -> String
}
class HeavyUIView: UIView { }
struct SwiftUIWrapper: UIViewRepresentable {
let wrappedView: HeavyUIView
let proxyDelegate = ProxyDelegate()
func makeUIView(
context: UIViewRepresentableContext<SwiftUIWrapper>
) -> some HeavyUIView {
wrappedView
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
// MARK: ViewModifiers
extension SwiftUIWrapper {
func heavyViewSomeThingHappened(
_ implementation: @escaping (
_ view: HeavyUIView,
_ thing: Int
) -> Void
) -> SwiftUIWrapper {
proxyDelegate.heavyViewSomeThingHappened = implementation
return self
}
func heavyViewTitleForThing(
_ implementation: @escaping (
_ view: HeavyUIView,
_ titleForThing: String
) -> String
) -> SwiftUIWrapper {
proxyDelegate.heavyViewTitleForThing = implementation
return self
}
}
// MARK: Coordinator
extension SwiftUIWrapper {
class Coordinator: HeavyUIViewDelegate {
let control: SwiftUIWrapper
init(_ control: SwiftUIWrapper) {
self.control = control
}
func heavyView(_ view: HeavyUIView, to thing: Int) {
control.proxyDelegate.heavyViewSomeThingHappened(view, thing)
}
func heavyView(_ view: HeavyUIView, titleForThing: String) -> String {
control.proxyDelegate.heavyViewTitleForThing(view, titleForThing)
}
}
}
// MARK: ProxyDelegate
extension SwiftUIWrapper {
class ProxyDelegate {
var heavyViewSomeThingHappened: (
_ view: HeavyUIView,
_ thing: Int
) -> Void = { view, thing in
// default implementation ...
}
var heavyViewTitleForThing: (
_ view: HeavyUIView,
_ titleForThing: String
) -> String = { view, titleForThing in
// default implementation ...
String(titleForThing.reversed())
}
}
}
// MARK: Example Callsite
SwiftUIWrapper(wrappedView: .init())
.heavyViewSomeThingHappened { view, thing in
// consumer provided implementation
}
.heavyViewTitleForThing { view, titleForThing in
"\(titleForThing.reversed()) - \(titleForThing)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment