Repository: expo/expo
File: packages/expo-dev-launcher/ios/ReactDelegateHandler/ExpoDevLauncherReactDelegateHandler.swift (Swift)

Code before:
// Copyright 2018-present 650 Industries. All rights reserved.

import ExpoModulesCore
import EXUpdatesInterface
import React

private class DevLauncherWrapperView: UIView {
  weak var devLauncherViewController: UIViewController?

#if !os(macOS)
  override func didMoveToWindow() {
    super.didMoveToWindow()

    guard let devLauncherViewController,
      let window,
      let rootViewController = window.rootViewController else {
      return
    }

    let isSwiftUIController = NSStringFromClass(type(of: rootViewController)).contains("UIHostingController")
    if !isSwiftUIController && devLauncherViewController.parent != rootViewController {
      rootViewController.addChild(devLauncherViewController)
      devLauncherViewController.didMove(toParent: rootViewController)
      devLauncherViewController.view.setNeedsLayout()
      devLauncherViewController.view.layoutIfNeeded()
    }
  }

  override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)
    if newWindow == nil {
      devLauncherViewController?.willMove(toParent: nil)
      devLauncherViewController?.removeFromParent()
    }
  }
#endif
}

@objc
public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, EXDevLauncherControllerDelegate {
  private weak var reactNativeFactory: RCTReactNativeFactory?
  private weak var reactDelegate: ExpoReactDelegate?
  private var launchOptions: [AnyHashable: Any]?
  private var rootViewModuleName: String?
  private var rootViewInitialProperties: [AnyHashable: Any]?
  private weak var rootViewController: UIViewController?


Review comment (suggestion):
Maybe we rename this to something more specific? `isSwiftUIController` is also only possible in brownfield 

Code after:
// Copyright 2018-present 650 Industries. All rights reserved.

import ExpoModulesCore
import EXUpdatesInterface
import React

private class DevLauncherWrapperView: UIView {
  weak var devLauncherViewController: UIViewController?

#if !os(macOS)
  override func didMoveToWindow() {
    super.didMoveToWindow()

    guard let devLauncherViewController,
      let window,
      let rootViewController = window.rootViewController else {
      return
    }

    let isSwiftUIController = NSStringFromClass(type(of: rootViewController)).contains("UIHostingController")
    // TODO(pmleczek): Revisit this for a more reliable solution
    let isBrownfield = NSStringFromClass(type(of: rootViewController)).contains("UINavigationController")
    if !isSwiftUIController && !isBrownfield && devLauncherViewController.parent != rootViewController {
      rootViewController.addChild(devLauncherViewController)
      devLauncherViewController.didMove(toParent: rootViewController)
      devLauncherViewController.view.setNeedsLayout()
      devLauncherViewController.view.layoutIfNeeded()
    }
  }

  override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)
    if newWindow == nil {
      devLauncherViewController?.willMove(toParent: nil)
      devLauncherViewController?.removeFromParent()
    }
  }
#endif
}

@objc
public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, EXDevLauncherControllerDelegate {
  private weak var reactNativeFactory: RCTReactNativeFactory?
  private weak var reactDelegate: ExpoReactDelegate?
  private var launchOptions: [AnyHashable: Any]?
  private var rootViewModuleName: String?
  private var rootViewInitialProperties: [AnyHashable: Any]?