iosswiftswiftuiasyncdisplaykit

How to wrap a SwiftUI View inside a ASDisplayNode


Today I was trying to figure out a way to interface SwiftUI and Texture (AsyncDisplayKit).

That way I get the speed and benefits of AsyncDisplayKit, ASNetworkImage, etc. and the flexibility of SwiftUI and Combine in my detail views.


Solution

  • Interfacing SwiftUI and Texture / AsyncDisplayKit

    We can initialize a node and provide a SwiftUI view to be used as the backing view. The Text view nests in a UIHostingController, a UIViewController subclass that represents a SwiftUI view within UIKit contexts.

    The view is provided via a block that will return a view so that the actual construction of the view can be saved until later. The node display step happens synchronously because a node can only be asynchronously displayed when it wraps an _ASDisplayView (the internal view subclass), not when it wraps a UIView.

    //
    //  HostingNode.swift
    //
    
    import AsyncDisplayKit
    import SwiftUI
    
    class HostingNode: ASDisplayNode {
    
        var viewController: UIViewController?
    
        override init() {
            super.init()
    
            setViewBlock { [weak self]() -> UIView in
                self?.viewController = self?.makeHostingController()
                return self?.viewController?.view ?? UIView()
            }
        }
    
        private func makeHostingController() -> UIViewController {
            UIHostingController(
                rootView: Text("Attention")
            )
        }
    }
    

    References: