Skip to content

Instantly share code, notes, and snippets.

@kaizeiyimi
Created October 22, 2019 07:27
Show Gist options
  • Save kaizeiyimi/17b13c7263b7069e538099a99f5efbe7 to your computer and use it in GitHub Desktop.
Save kaizeiyimi/17b13c7263b7069e538099a99f5efbe7 to your computer and use it in GitHub Desktop.
SwiftUI+UIKit Preview
import SwiftUI
import UIKit
@available(iOS 13, *)
public enum UIKitRepresentable {
public static func view<V, Model>(
viewType: V.Type = V.self, model: Model,
make: @escaping ((context: UIViewRepresentableContext<_UIKitView<V,Model, Void>>, model: Model)) -> V,
update: (((uiView: V, context: UIViewRepresentableContext<_UIKitView<V,Model, Void>>, model: Model)) -> Void)? = nil,
dismantle: (((uiView: V, coordinator: Void)) -> Void)? = nil) -> _UIKitView<V, Model, Void> {
return _UIKitView(viewType: viewType, model: model, coordinator: {},
make: make, update: update, dismantle: dismantle)
}
public static func view<V, Model, COO>(
viewType: V.Type = V.self, model: Model,
coordinator: @escaping () -> COO,
make: @escaping ((context: UIViewRepresentableContext<_UIKitView<V,Model, COO>>, model: Model)) -> V,
update: (((uiView: V, context: UIViewRepresentableContext<_UIKitView<V,Model, COO>>, model: Model)) -> Void)? = nil,
dismantle: (((uiView: V, coordinator: COO)) -> Void)? = nil) -> _UIKitView<V, Model, COO> {
return _UIKitView(viewType: viewType, model: model, coordinator: coordinator,
make: make, update: update, dismantle: dismantle)
}
public static func viewController<VC, Model>(
vcType: VC.Type = VC.self, model: Model,
make: @escaping ((context: UIViewControllerRepresentableContext<_UIKitViewController<VC, Model, Void>>, model: Model)) -> VC,
update: (((uiViewController: VC, context: UIViewControllerRepresentableContext<_UIKitViewController<VC, Model, Void>>, model: Model)) -> Void)? = nil,
dismantle: (((uiViewController: VC, coordinator: Void)) -> Void)? = nil) -> _UIKitViewController<VC, Model, Void> {
return _UIKitViewController(vcType: vcType, model: model, coordinator: {},
make: make, update: update, dismantle: dismantle)
}
public static func viewController<VC, Model, COO>(
vcType: VC.Type = VC.self, model: Model,
coordinator: @escaping () -> COO,
make: @escaping ((context: UIViewControllerRepresentableContext<_UIKitViewController<VC, Model, COO>>, model: Model)) -> VC,
update: (((uiViewController: VC, context: UIViewControllerRepresentableContext<_UIKitViewController<VC, Model, COO>>, model: Model)) -> Void)? = nil,
dismantle: (((uiViewController: VC, coordinator: COO)) -> Void)? = nil) -> _UIKitViewController<VC, Model, COO> {
return _UIKitViewController(vcType: vcType, model: model, coordinator: coordinator,
make: make, update: update, dismantle: dismantle)
}
private static var associationKey = "FunctionWrapper.dismantle.association.key"
private final class DismantleWrapper<V, COO>: NSObject {
let exec: (V, COO) -> Void
init(_ exec: @escaping (V, COO) -> Void) {
self.exec = exec
super.init()
}
}
}
// MARK: - UIView
@available(iOS 13, *)
extension UIKitRepresentable {
public struct _UIKitView<V: UIView, Model, COO>: UIViewRepresentable {
private let model: Model
private let coordinator: () -> COO
private let make: ((context: Context, model: Model)) -> V
private let update: (((uiView: V, context: Context, model: Model)) -> Void)?
private let dismantle: (((uiView: V, coordinator: COO)) -> Void)?
fileprivate init(viewType: V.Type = V.self, model: Model,
coordinator: @escaping () -> COO,
make: @escaping ((context: Context, model: Model)) -> V,
update: (((uiView: V, context: Context, model: Model)) -> Void)? = nil,
dismantle: (((uiView: V, coordinator: COO)) -> Void)? = nil) {
self.model = model
self.coordinator = coordinator
self.make = make
self.update = update
self.dismantle = dismantle
}
public func makeCoordinator() -> COO {
return coordinator()
}
public func makeUIView(context: Context) -> V {
let view = make((context, model))
if let dismantle = dismantle {
let wrapper = DismantleWrapper<V, COO>{ dismantle(($0, $1)) }
objc_setAssociatedObject(view, &associationKey, wrapper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return view
}
public func updateUIView(_ uiView: V, context: Context) {
update?((uiView, context, model))
}
public static func dismantleUIView(_ uiView: V, coordinator: COO) {
if let wrapper = objc_getAssociatedObject(uiView, &associationKey) as? DismantleWrapper<V, COO> {
wrapper.exec(uiView, coordinator)
}
}
}
}
// MARK: - UIViewController
@available(iOS 13, *)
extension UIKitRepresentable {
public struct _UIKitViewController<VC: UIViewController, Model, COO>: UIViewControllerRepresentable {
private let model: Model
private let coordinator: () -> COO
private let make: ((context: Context, model: Model)) -> VC
private let update: (((uiViewController: VC, context: Context, model: Model)) -> Void)?
private let dismantle: (((uiViewController: VC, coordinator: COO)) -> Void)?
fileprivate init(vcType: VC.Type = VC.self, model: Model,
coordinator: @escaping () -> COO,
make: @escaping ((context: Context, model: Model)) -> VC,
update: (((uiViewController: VC, context: Context, model: Model)) -> Void)? = nil,
dismantle: (((uiViewController: VC, coordinator: COO)) -> Void)? = nil) {
self.model = model
self.coordinator = coordinator
self.make = make
self.update = update
self.dismantle = dismantle
}
public func makeCoordinator() -> COO {
return coordinator()
}
public func makeUIViewController(context: Context) -> VC {
let vc = make((context, model))
if let dismantle = dismantle {
let wrapper = DismantleWrapper<VC, COO>{ dismantle(($0, $1)) }
objc_setAssociatedObject(vc, &associationKey, wrapper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return vc
}
public func updateUIViewController(_ uiViewController: VC, context: Context) {
update?((uiViewController, context, model))
}
public static func dismantleUIViewController(_ uiViewController: VC, coordinator: COO) {
if let wrapper = objc_getAssociatedObject(uiViewController, &associationKey) as? DismantleWrapper<VC, COO> {
wrapper.exec(uiViewController, coordinator)
}
}
}
}
@jeudesprits
Copy link

jeudesprits commented Apr 16, 2020

@kaizeiyimi Hi! Very interested in your code. Can you tell me how to use it?

@timothybowers
Copy link

@kaizeiyimi I would also like to know more about this code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment