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
}
}