【问题标题】:Cannot switch to another child view controller in container view无法在容器视图中切换到另一个子视图控制器
【发布时间】:2018-12-17 15:45:52
【问题描述】:

我有一个主视图控制器、一个容器视图和 2 个子视图控制器,我希望能够在子视图控制器之间切换(例如:当应用程序第一次加载时,我希望控制器包含要加载的 MapView,当我按下在主视图中找到的搜索栏时,带有要加载的表的控制器)。 这是我的故事板:https://i.stack.imgur.com/rDPMe.png

MainScreen.swift

class MainScreen: UIViewController {

@IBOutlet private weak var searchBar: UISearchBar!
@IBOutlet private weak var ContainerView: UIView!
//private var openSearchBar: Bool?
private var openMapView: Bool = true
private var openPlacesList: Bool = false
private var containerView: ContainerViewController!

override func viewDidLoad() {
    super.viewDidLoad()
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    //let containerView = segue.destination as? ContainerViewController
    if containerView == nil{
        containerView = segue.destination as? ContainerViewController
    }
    if openMapView == true{
        containerView!.moveToMapView()
    }
    else if openPlacesList == true{
        containerView!.MoveToOpenPlaces()
    }
  }
}
//search bar delegate functions
extension MainScreen: UISearchBarDelegate{
//detects when text is entered
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    openPlacesList = true
    openMapView = false
    containerView!.MoveToOpenPlaces()
  }
}

ContainerViewController.swift:

class ContainerViewController: UIViewController {

private var childViewController: UIViewController!

private var first: UIViewController?
private var sec: UIViewController?

override func viewDidLoad() {
    super.viewDidLoad()
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.identifier == "MainToMap"{

        first = segue.destination as! MapViewController
        self.addChild(first!)
        self.view.addSubview(first!.view)
        self.didMove(toParent: self)
    }else{
       sec = segue.destination as! PlacesListController
    }

    if(first != nil && sec != nil){
        interchange(first!,sec!)
    }
}

func interchange(_ oldVc: UIViewController,_ newVc: UIViewController ){
    oldVc.willMove(toParent: nil)
    self.addChild(newVc)
    self.view.addSubview(newVc.view)

    self.transition(from: oldVc, to: newVc, duration: 2, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
        newVc.view.alpha = 1
        oldVc.view.alpha = 0
    }, completion: { (complete) in
        oldVc.view.removeFromSuperview()
        oldVc.removeFromParent()
        newVc.willMove(toParent: self)
    })
}

func moveToMapView(){
    performSegue(withIdentifier: "MainToMap", sender: nil)
}

func MoveToOpenPlaces(){
    performSegue(withIdentifier: "MainToSearches", sender: nil)
}

}

问题是当我按下搜索栏时,它会调用方法交换,然后它只会给出一个 SIGABRT 1 错误。我试过这个教程:https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html#//apple_ref/doc/uid/TP40007457-CH11-SW1 等等,但到目前为止还没有运气。我被困在这里,不知道如何解决这个问题。

堆栈:https://i.stack.imgur.com/Zqpm1.png SIGABR 1 错误:https://i.stack.imgur.com/NBgEN.png

【问题讨论】:

  • "那么它只会给出一个 SIGABRT 1 错误":当它发生时,您在控制台中是否有错误日志?如果是,你能分享它的内容吗?
  • 嗨。它只是这样说:“libc++abi.dylib:以 NSException 类型的未捕获异常终止”。我还用堆栈添加了一张图片。
  • 您能否复制/粘贴“libc++abi.dylib:以未捕获的 NSException 类型异常终止”的完整错误并用它编辑您的问题?
  • 我怎样才能得到完整的错误?它只是这么说的。
  • 上面什么都没有?

标签: ios swift uitableview mkmapview


【解决方案1】:

您似乎正在尝试在子视图控制器之间手动转换,但同时使用 segues(它们为您进行自己的转换)。消除转场(除了最初的嵌入转场,如果您使用的是带有“容器视图”的情节提要),并使用他们的情节提要 ID 手动实例化子视图控制器。但是不要使用segues然后尝试替换prepare(for:sender:)中的子视图控制器。

另外,当您使用transition(from:to:duration:options:animations:completion:) 时,您不应自己将视图添加到视图层次结构中。该方法为您执行此操作(除非您使用 showHideTransitionViews 选项,它告诉该方法您正在接管它,我们不需要在此处执行此操作)。同样,当您使用 transitionCrossDissolve 选项时,您也不需要弄乱 alpha。


因此,使用您引用的那篇文章中的代码 sn-p,您可以:

class FirstViewController: UIViewController {

    @IBOutlet weak var containerView: UIView!  // the view for the storyboard's "container view"
    @IBOutlet weak var redButton: UIButton!    // a button to transition to the "red" child view controller
    @IBOutlet weak var blueButton: UIButton!   // a button to transition to the "blue" child view controller

    // tapped on "transition to red child view controller" button

    @IBAction func didTapRedButton(_ sender: UIButton) {
        redButton.isEnabled = false
        blueButton.isEnabled = true

        let oldVC = children.first!
        let newVC = storyboard!.instantiateViewController(withIdentifier: "RedStoryboardID")
        cycle(from: oldVC, to: newVC)
    }

    // tapped on "transition to blue child view controller" button

    @IBAction func didTapBlueButton(_ sender: UIButton) {
        blueButton.isEnabled = false
        redButton.isEnabled = true

        let oldVC = children.first!
        let newVC = storyboard!.instantiateViewController(withIdentifier: "BlueStoryboardID")
        cycle(from: oldVC, to: newVC)
    }

    func cycle(from oldVC: UIViewController, to newVC: UIViewController) {
        // Prepare the two view controllers for the change.
        oldVC.willMove(toParent: nil)
        addChild(newVC)

        // Get the final frame of the new view controller.
        newVC.view.frame = containerView.bounds

        // Queue up the transition animation.
        transition(from: oldVC, to: newVC, duration: 0.25, options: .transitionCrossDissolve, animations: {
            // this is intentionally blank; transitionCrossDissolve will do the work for us
        }, completion: { finished in
            oldVC.removeFromParent()
            newVC.didMove(toParent: self)
        })
    }

    func display(_ child: UIViewController) {
        addChild(child)
        child.view.frame = containerView.bounds
        containerView.addSubview(child.view)
        child.didMove(toParent: self)
    }

    func hide(_ child: UIViewController) {
        child.willMove(toParent: nil)
        child.view.removeFromSuperview()
        child.removeFromParent()
    }

}

产生:

【讨论】:

  • 非常感谢您的帮助:)。错误不再出现。但是现在当我实例化控制器时,来自 MapViewController 的地图视图不会出现。这只是一个空白页。我使用了调试器,它说它是零。我必须在容器中实例化地图视图吗?
  • 在我的示例中,我使用情节提要“容器”视图设置了默认子视图控制器(将其嵌入到默认子视图控制器的场景中),因此初始视图控制器包含的东西是自动完成。但如果您愿意,您也可以在viewDidLoad 中以编程方式(使用display 方法)执行此操作。您始终可以使用 Xcode 中的视图调试器来确认孩子是否已正确实例化以及 frame 是什么,并确保问题也不是缺少出口。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-10
  • 2021-12-31
  • 2016-01-11
  • 1970-01-01
  • 2015-03-23
相关资源
最近更新 更多