0

I have a code feature to switch UIViewController, which works great on iPhone but crashes on iPad. It works fine at times but crashes at others. Can you assist me in determining what is wrong with it? I've included the complete code below.

The crash message:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[<My app name>.TheiPadMainView isOnScreen]: unrecognized selector sent to instance 0x114e3e500'
terminating with uncaught exception of type NSException

My SceneDelegate:

window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene

if UIDevice.current.userInterfaceIdiom == .phone { window?.rootViewController = UINavigationController(rootViewController: LauncherScreen()) }
else { window?.rootViewController = LauncherScreen() }

window?.makeKeyAndVisible()

My startup (loading) code:

DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
   if self.isLargeDevice() { // If iPad isn't iPad mini
      self.goToNewView(theController: TheiPadMainView())
   } else { // All iPhone and iPad mini
      self.goToNewView(theController: UINavigationController(rootViewController: TheTabbar()))
   }
})

Create new window:

func goToNewView(theController: UIViewController) {
    let windowScenes = UIApplication.shared.connectedScenes.first as? UIWindowScene
    let window = windowScenes?.windows.first
    window?.setRootViewController(theController, options: .init(direction: .fade, style: .linear))
}

Switch window supporter, this what it give me error

extension UIWindow {
    struct TransitionOptions {
        public enum Curve {
            case linear
            case easeIn
            case easeOut
            case easeInOut
            
            internal var function: CAMediaTimingFunction {
                let key: String!
                switch self {
                case .linear: key = CAMediaTimingFunctionName.linear.rawValue
                case .easeIn: key = CAMediaTimingFunctionName.easeIn.rawValue
                case .easeOut: key = CAMediaTimingFunctionName.easeOut.rawValue
                case .easeInOut: key = CAMediaTimingFunctionName.easeInEaseOut.rawValue
                }
                return CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: key!))
            }
        }
        
        public enum Direction {
            case fade
            case toTop
            case toBottom
            case toLeft
            case toRight
            
            internal func transition() -> CATransition {
                let transition = CATransition()
                transition.type = CATransitionType.push
                switch self {
                case .fade:
                    transition.type = CATransitionType.fade
                    transition.subtype = nil
                case .toLeft:
                    transition.subtype = CATransitionSubtype.fromLeft
                case .toRight:
                    transition.subtype = CATransitionSubtype.fromRight
                case .toTop:
                    transition.subtype = CATransitionSubtype.fromTop
                case .toBottom:
                    transition.subtype = CATransitionSubtype.fromBottom
                }
                return transition
            }
        }
        
        public enum Background {
            case solidColor(_: UIColor)
            case customView(_: UIView)
        }
        
        public var duration: TimeInterval = 0.5
        
        public var direction: TransitionOptions.Direction = .toRight
        
        public var style: TransitionOptions.Curve = .linear
        
        public var background: TransitionOptions.Background? = nil
        
        public init(direction: TransitionOptions.Direction = .toRight, style: TransitionOptions.Curve = .linear) {
            self.direction = direction
            self.style = style
        }
        
        public init() { }
        
        internal var animation: CATransition {
            let transition = self.direction.transition()
            transition.duration = self.duration
            transition.timingFunction = self.style.function
            return transition
        }
    }
    
    func setRootViewController(_ controller: UIViewController, options: TransitionOptions = TransitionOptions()) {
        var transitionWnd: UIWindow? = nil
        if let background = options.background {
            transitionWnd = UIWindow(frame: UIScreen.main.bounds)
            switch background {
            case .customView(let view):
                transitionWnd?.rootViewController = UIViewController.newController(withView: view, frame: transitionWnd!.bounds)
            case .solidColor(let color):
                transitionWnd?.backgroundColor = color
            }
            transitionWnd?.makeKeyAndVisible()
        }
        
        // Make animation
        self.layer.add(options.animation, forKey: kCATransition)
        self.rootViewController = controller
        self.makeKeyAndVisible() // !!! CRASH WENT HERE !!!
        
        if let wnd = transitionWnd {
            DispatchQueue.main.asyncAfter(deadline: (.now() + 1 + options.duration), execute: {
                wnd.removeFromSuperview()
            })
        }
    }
}

internal extension UIViewController {
    static func newController(withView view: UIView, frame: CGRect) -> UIViewController {
        view.frame = frame
        let controller = UIViewController()
        controller.view = view
        return controller
    }
}
Travgalax
  • 81
  • 1
  • 7

0 Answers0