From 677ee90b463870256efaf493f299ddb2d6a97836 Mon Sep 17 00:00:00 2001 From: Isaac Israel Date: Wed, 24 Jun 2026 11:38:39 +0300 Subject: [PATCH] fix(ios): defer SwiftUI host setup until reactViewController is ready setupView() assigned self.hostingController before verifying that reactViewController() was non-nil. On the first didMoveToWindow pass the React view controller can still be nil, so the `if let ... reactViewController()` block was skipped and the SwiftUI hosting view was never added or pinned (its frame stayed .zero, rendering the page blank). Because self.hostingController was already set, the early-return guard then blocked every later retry, so the pager stayed blank for the lifetime of the view. Timing-dependent, so it reproduced intermittently. Guard on reactViewController() before creating/assigning the hosting controller, and retry setupView() from layoutSubviews() so attachment happens as soon as the view controller hierarchy is ready. Co-authored-by: Cursor --- ios/PagerViewProvider.swift | 38 ++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/ios/PagerViewProvider.swift b/ios/PagerViewProvider.swift index 54fb5177..1b1e8754 100644 --- a/ios/PagerViewProvider.swift +++ b/ios/PagerViewProvider.swift @@ -91,6 +91,13 @@ import UIKit } } + override public func layoutSubviews() { + super.layoutSubviews() + if window != nil { + setupView() + } + } + @objc public func goTo(index: Int, animated: Bool) { if animated { withAnimation { @@ -106,19 +113,32 @@ import UIKit return } - self.hostingController = UIHostingController( + // Only create the hosting controller once it can actually be attached to the + // React view-controller hierarchy. `reactViewController()` can be nil on the + // first `didMoveToWindow` pass (e.g. when the pager is mounted inside a screen + // that is still being attached). Previously `self.hostingController` was + // assigned before this check, so when `reactViewController()` was nil the + // SwiftUI host was never added/pinned (its view frame stayed `.zero`, leaving + // the page blank) while the early-return above prevented any later retry. + // Deferring keeps `hostingController` nil so a subsequent window/layout pass + // can attach it once the view controller is available. + guard let parentViewController = reactViewController() else { + return + } + + let hostingController = UIHostingController( rootView: PagerView(props: props, delegate: delegate), ignoreSafeArea: true ) - if let hostingController, let parentViewController = reactViewController() { - parentViewController.addChild(hostingController) - hostingController.view.backgroundColor = .clear - addSubview(hostingController.view) + self.hostingController = hostingController - hostingController.view.translatesAutoresizingMaskIntoConstraints = false - hostingController.view.pinEdges(to: self) + parentViewController.addChild(hostingController) + hostingController.view.backgroundColor = .clear + addSubview(hostingController.view) - hostingController.didMove(toParent: parentViewController) - } + hostingController.view.translatesAutoresizingMaskIntoConstraints = false + hostingController.view.pinEdges(to: self) + + hostingController.didMove(toParent: parentViewController) } }