在分离的视图控制器上呈现视图控制器

时间:2014-08-20 09:59:52

标签: ios swift viewcontroller

我有sideViewController个按钮和Action,它通过单击此按钮显示新的视图控制器。

class sideViewController: UIViewController {
    @IBOutlet var buttonVC1 : UIButton!
    @IBAction func goToVC1 () {
        var VC1 = self.storyboard.instantiateViewControllerWithIdentifier("ViewController") as ViewController
        presentViewController(VC1, animated:true, completion: nil)
    }
}

我在主视图控制器中使用它:

class ViewController: UIViewController {
    var menu : sideViewController!
    override func viewDidLoad() {
        super.viewDidLoad()
        menu = self.storyboard.instantiateViewControllerWithIdentifier("menu") as      sideViewController
        menu.view.frame = CGRect(x: 0, y: 0, width: 160, height: 480)
        view.addSubview(menu.view)
}

当我单击此按钮时,问题是:"不鼓励在分离的视图控制器上显示视图控制器"

我该怎么做才能解决这个问题?

5 个答案:

答案 0 :(得分:9)

我自己也遇到了同样的警告,并意识到我得到它是因为我打电话时

self.presentViewController

我在视图控制器上调用它,该视图控制器没有通过视图层次结构附加到UIWindow。您需要更改正在执行的操作以延迟调用presentViewController,直到您知道视图位于视图堆栈上。这可以在ViewDidLoad或ViewDidAppear中完成,或者如果您来自后台状态,等待您的应用处于活动状态

答案 1 :(得分:4)

使用它来确保你在主线程上

dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.presentViewController(VC1, animated: true, completion: nil)
    })

答案 2 :(得分:2)

问题

iOS正在抱怨主视图之后出现的其他一些视图(独立视图)。它可以呈现它,它显然可以表现出来,但它不鼓励这样做。

解决方案

委托/协议模式适合解决此问题。通过使用此模式,操作将在SideVC内触发,尽管此触发器将发送到MainVC并在那里执行。

因此,由于动作将由MainVC触发,从iOS的角度来看,它将是安全无虞的。

代码

<强> SideVC:

protocol SideVCDelegate: class {
  func sideVCGoToVC1()
}

class sideVC: UIViewController {
  weak var delegate: SideVCDelegate?

  @IBOutlet var buttonVC1: UIButton!

  @IBAction func goToVC1 () {
    delegate.sideVCGoToVC1()
  }

<强> MainVC

class MainVC: UIViewController, SideVCDelegate {
  var menu: sideVC!

  override func viewDidLoad() {
    super.viewDidLoad()
    menu = self.storyboard?.instantiateViewControllerWithIdentifier("menu") as sideViewController
    menu.delegate = self
    menu.view.frame = CGRect(x: 0, y: 0, width: 160, height: 480)
    view.addSubview(menu.view)
  }

  // MARK: - SideViewControllerDelegate
  func sideViewControllerGoToVC1() {
    menu.view.removeFromSuperview()
    var VC1 = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController") as ViewController
    presentViewController(VC1, animated:true, completion: nil)
  }
}

注意

除了你提出的问题外,以下几行看起来有些模糊。

var VC1 = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController") as ViewController
menu.view.frame = CGRect(x: 0, y: 0, width: 160, height: 480)

您在故事板中获取了一个视图控制器,当您在Interface Builder中设计它时,该视图控制器有一个框架,但您之后会对其进行更改。一旦他们创建了视图框架,这不是一个好习惯。

也许您打算做其他事情,但最有可能的是,这是一段有问题的代码。

答案 3 :(得分:0)

这可能会对您有所帮助。我用这个

修复了我的错误
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC)))

dispatch_after(time, dispatch_get_main_queue(), { () -> Void in
   self.performSegueWithIdentifier("SegueName", sender: self)
})
祝你好运..

答案 4 :(得分:0)

快捷键5

在UIKit视图层次结构中,视图控制器可以“附加”或“分离”,我在引号中加了引号,因为它们在文档中从未进行过解释。根据我的观察,附加的视图控制器只是直接链接到键窗口的视图控制器。

因此,最接近的附加视图控制器显然是根视图控制器本身,因为它直接由键窗口拥有。这就是为什么从根视图控制器进行呈现可以弥补有关在分离的视图控制器上呈现的警告的原因。

要显示后续的视图控制器(第二个),您必须找到下一个最近且可用的附加视图控制器(我说是可用的,因为当前视图控制器正在占用根视图控制器;无法再显示其他视图)控制器)。如果根目录提供一个普通视图控制器(意味着,不是像导航控制器这样的容器视图控制器),那么下一个最接近的附加视图控制器就是该视图控制器。您可以从self进行显示,而不会发出任何警告,因为它直接链接到根,后者直接链接到键窗口。但是,如果根目录提供了容器视图控制器(如导航控制器),则您将无法从其任何子目录中进行展示,因为它们的子目录没有直接链接到根目录,即父目录/容器目录。因此,您必须从父母/容器出示。

为简化此操作,您可以将UIViewController子类化,并添加一种便捷的方法来查找最接近的可用附加视图控制器。

class XViewController: UIViewController {
    var rootViewController: UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController
    }
    
    /* Returns the nearest available attached view controller
       (for objects that seek to present view controllers). */
    var nearestAvailablePresenter: UIViewController? {
        guard let root = rootViewController else {
            return nil
        }
        if root.presentedViewController == nil {
            return root // the root is not presenting anything, use the root
        } else if let parent = parent {
            return parent // the root is currently presenting, find nearest parent
        } else {
            return self // no parent found, present from self
        }
    }
}

用法

class SomeViewController: XViewController {
    let modal = AnotherViewController()
    nearestAvailablePresenter?.present(modal, animated: true, completion: nil)
}