He encontrado algunas publicaciones para este problema, pero ninguna resolvió mi problema.
Di como si ...
- ViewControllerA
- ViewControllerB
Intenté agregar ViewControllerB como una subvista en ViewControllerA pero arroja un error como " fatal error: unexpectedly found nil while unwrapping an Optional value
".
A continuación se muestra el código ...
ViewControllerA
var testVC: ViewControllerB = ViewControllerB();
override func viewDidLoad()
{
super.viewDidLoad()
self.testVC.view.frame = CGRectMake(0, 0, 350, 450);
self.view.addSubview(testVC.view);
// Do any additional setup after loading the view.
}
ViewControllerB es solo una pantalla simple con una etiqueta en ella.
ViewControllerB
@IBOutlet weak var test: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
test.text = "Success" // Throws ERROR here "fatal error: unexpectedly found nil while unwrapping an Optional value"
}
EDITAR
Con la solución sugerida de las respuestas del usuario, ViewControllerB en ViewControllerA está saliendo de la pantalla. El borde gris es el marco que he creado para la subvista.
fuente
ViewControllerB
aViewControllerA
,ViewControllerB
se apaga la pantalla. He editado mi publicación con la captura de pantalla del simulador.frame
manualmente. O si lo apagatranslatesFrameIntoConstraints
(o como se llame), y probablemente también pueda agregar restricciones mediante programación. Pero si está agregando la subvista, es responsable de configurar su marco, de una forma u otra, al igual que para todas las subvistas agregadas mediante programación.controller.view.frame = UIScreen.mainScreen().bounds
addSubview
, la vista raíz del controlador secundario es una subvista de la vista a la que lo agregó. Todo lo que debe hacer es agregar restricciones entre la vista raíz del controlador secundario y la vista a la que acaba de agregarlo como una subvista.Gracias a Rob. Añadiendo sintaxis detallada para su segunda observación:
let controller:MyView = self.storyboard!.instantiateViewControllerWithIdentifier("MyView") as! MyView controller.ANYPROPERTY=THEVALUE // If you want to pass value controller.view.frame = self.view.bounds self.view.addSubview(controller.view) self.addChildViewController(controller) controller.didMoveToParentViewController(self)
Y para eliminar el viewcontroller:
self.willMoveToParentViewController(nil) self.view.removeFromSuperview() self.removeFromParentViewController()
fuente
addChildViewController
, no llamewillMoveToParentViewController
. LlamaraddChildViewController
lo llamará por ti. Consulte Agregar y eliminar un niño en la Guía de programación de View Controller para iOS. Por esta razón, personalmente siempre llamaríaaddChildViewController
inmediatamente después de crear una instancia, pero antes de configurarlo.This code will work for Swift 4.2. let controller:SecondViewController = self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as! SecondViewController controller.view.frame = self.view.bounds; self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self)
fuente
willMove
.addChild
hace eso por ti. Consulte lawillMove
documentación . Entonces la secuencia es (1)addChild
; (2) configure la vista del vc secundario y agréguela a la jerarquía de vista; y (3) llamardidMove(toParent:)
Para agregar y quitar ViewController
var secondViewController :SecondViewController? // Adding func add_ViewController() { let controller = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController")as! SecondViewController controller.view.frame = self.view.bounds self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self) self.secondViewController = controller } // Removing func remove_ViewController(secondViewController:SecondViewController?) { if secondViewController != nil { if self.view.subviews.contains(secondViewController!.view) { secondViewController!.view.removeFromSuperview() } } }
fuente
willMove
. Como dice lawillMove
documentación , loaddChild
hace por usted.func callForMenuView () {
if(!isOpen) { isOpen = true let menuVC : MenuViewController = self.storyboard!.instantiateViewController(withIdentifier: "menu") as! MenuViewController self.view.addSubview(menuVC.view) self.addChildViewController(menuVC) menuVC.view.layoutIfNeeded() menuVC.view.frame=CGRect(x: 0 - UIScreen.main.bounds.size.width, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height); UIView.animate(withDuration: 0.3, animations: { () -> Void in menuVC.view.frame=CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height); }, completion:nil) }else if(isOpen) { isOpen = false let viewMenuBack : UIView = view.subviews.last! UIView.animate(withDuration: 0.3, animations: { () -> Void in var frameMenu : CGRect = viewMenuBack.frame frameMenu.origin.x = -1 * UIScreen.main.bounds.size.width viewMenuBack.frame = frameMenu viewMenuBack.layoutIfNeeded() viewMenuBack.backgroundColor = UIColor.clear }, completion: { (finished) -> Void in viewMenuBack.removeFromSuperview() }) }
fuente
Gracias a Rob, se actualizó la sintaxis de Swift 4.2
let controller:WalletView = self.storyboard!.instantiateViewController(withIdentifier: "MyView") as! WalletView controller.view.frame = self.view.bounds self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self)
fuente
willMove
. Como dice lawillMove
documentación , loaddChild
hace por usted. No se obtiene nada bueno de llamarlo dos veces.Consulte también la documentación oficial sobre la implementación de un controlador de vista de contenedor personalizado:
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html#//apple_ref/doc/uid/TP40007457-CH11-SW1
Esta documentación tiene información mucho más detallada para cada instrucción y también describe cómo agregar transiciones.
Traducido a Swift 3:
func cycleFromViewController(oldVC: UIViewController, newVC: UIViewController) { // Prepare the two view controllers for the change. oldVC.willMove(toParentViewController: nil) addChildViewController(newVC) // Get the start frame of the new view controller and the end frame // for the old view controller. Both rectangles are offscreen.r newVC.view.frame = view.frame.offsetBy(dx: view.frame.width, dy: 0) let endFrame = view.frame.offsetBy(dx: -view.frame.width, dy: 0) // Queue up the transition animation. self.transition(from: oldVC, to: newVC, duration: 0.25, animations: { newVC.view.frame = oldVC.view.frame oldVC.view.frame = endFrame }) { (_: Bool) in oldVC.removeFromParentViewController() newVC.didMove(toParentViewController: self) } }
fuente