Ios 将子视图控制器添加到当前视图控制器

Ios 将子视图控制器添加到当前视图控制器,ios,objective-c,uinavigationcontroller,Ios,Objective C,Uinavigationcontroller,我正在尝试使用以下代码在代码中将子视图控制器添加到故事板中的当前视图控制器: UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil]; LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init]; lvc = (LogInTutorialViewController *)[storyboard i

我正在尝试使用以下代码在代码中将子视图控制器添加到故事板中的当前视图控制器:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];
lvc = (LogInTutorialViewController *)[storyboard instantiateViewControllerWithIdentifier:@"LogInTutorialViewControllerID"];
[self displayContentController:lvc];

- (void) displayContentController: (LogInTutorialViewController*) content;
{

    //add as childViewController
    [self addChildViewController:content];
    [content didMoveToParentViewController:self];
    [content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
    [self.view addSubview:content.view];

}
该视图似乎至少显示在模拟器上,但在控制台中,我发现了很多错误:

 <Error>: CGContextSaveGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context  and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.
:CGContextSaveGState:无效的上下文0x0。这是一个严重的错误。此应用程序或其使用的库正在使用无效的上下文,从而导致系统稳定性和可靠性的整体降级。此通知是出于礼貌:请解决此问题。这将成为即将进行的更新中的致命错误。
以及相同的描述但不同的错误:

CGContextSetLineWidth、CGContextSetLineJoin、CGContextSetLineCap、CGContextSetMiterLimit、CGContextSetFlatness、CGContextAddPath、CGContextDrawPath、CGContextRestoreGState

所有这些错误都会记录两次

有人知道我做错了什么吗


我也读了一些帖子,在一些帖子中,有人建议在传递数据之前alloc和init视图控制器,我也尝试了,但没有任何运气。

didMoveToParentViewController必须是最后一个。

为什么不尝试此代码来添加视图,我认为这是一个简单易行的代码

self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:@"LOGIN"];
[self addChildViewController:self.loginView];
[self.loginView.view setFrame:CGRectMake(0.0f, 0.0f, self.contentView.frame.size.width, self.contentView.frame.size.height)];
[self.contentView addSubview:self.loginView.view];
[self.loginView didMoveToParentViewController:self]; 
有关更多信息,请查看此项。

  • 在Interface Builder中配置容器
要在设计时创建父子容器关系,请将容器视图对象添加到情节提要场景中,如下图所示。容器视图对象是表示子视图控制器内容的占位符对象。使用该视图可以相对于容器中的其他视图调整子级根视图的大小和位置

加载带有一个或多个容器视图的视图控制器时,Interface Builder还会加载与这些视图关联的子视图控制器。子对象必须与父对象同时实例化,以便创建适当的父子关系

如果不使用Interface Builder设置父子容器关系,则必须通过将每个子容器添加到容器视图控制器来以编程方式创建这些关系,如将子视图控制器添加到内容中所述

  • 将子视图控制器添加到内容中
要以编程方式将子视图控制器合并到内容中,请通过执行以下操作在相关视图控制器之间创建父子关系:

  • 调用容器视图控制器的
    addChildViewController:
    方法。 此方法告诉UIKit您的容器视图控制器现在正在管理子视图控制器的视图
  • 将子级的根视图添加到容器的视图层次结构中。 在这个过程中,请始终记住设置儿童框架的大小和位置
  • 添加用于管理子级根视图的大小和位置的任何约束
  • 调用子视图控制器的didMoveToParentViewController:方法
  • 这是代码

    - (void)displayContentController:(UIViewController *)content {
        [self addChildViewController:content];
        content.view.frame = [self frameForContentController];
        [self.view addSubview:self.currentClientView];
        [content didMoveToParentViewController:self];
    }
    
    Swift

    func displayContentController(_ content: UIViewController?) {
    if let content = content {
        addChild(content)
    }
    content?.view.frame = frameForContentController()
    view.addSubview(currentClientView)
    content?.didMove(toParent: self)
    
    }


    关于同一示例的更多详细说明,请参见Swift中的解决方案(撰写本文时为Swift 4):

    注:

    • 故事板名称为“Main”
    • 情节提要中的视图控制器标识符名为“登录”
    • 这将使用故事板创建加载视图控制器,但同样可以通过编程方式完成。在尝试访问视图的框架之前,请确保视图已加载到内存中,否则会发生崩溃(执行类似于以模态方式呈现视图控制器的操作)

    您还可以创建一个扩展,用于添加和删除
    UIViewController

    extension UIViewController {
        func addChildViewControllerWithView(_ childViewController: UIViewController, toView view: UIView? = nil) {
            let view: UIView = view ?? self.view
            childViewController.removeFromParent()
            childViewController.willMove(toParent: self)
            addChild(childViewController)
            childViewController.didMove(toParent: self)
            childViewController.view.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(childViewController.view)
            view.addConstraints([
                NSLayoutConstraint(item: childViewController.view!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
            ])
            view.layoutIfNeeded()
        }
    
        func removeChildViewController(_ childViewController: UIViewController) {
            childViewController.removeFromParent()
            childViewController.willMove(toParent: nil)
            childViewController.removeFromParent()
            childViewController.didMove(toParent: nil)
            childViewController.view.removeFromSuperview()
            view.layoutIfNeeded()
        }
    }
    

    每当您想在
    viewdiload()
    方法中添加
    UIViewController
    时,您需要调用
    addChildViewControllerWithView(someVC)

    当我到达以下行时,所有错误都会被记录下来:[content.view setFrame:CGRectMake(0,0[UIScreen mainScreen].bounds.size.width[UIScreen mainScreen].bounds.size.height];尝试先添加子视图,然后将其设置为框架。现在我怀疑问题与子视图控制器视图中的内容有关,而不是父子关系。尝试了下一个代码:[self addChildViewController:content];[self.view addSubview:content.view];[content-didMoveToParentViewController:self];[content.view setFrame:CGRectMake(0,0[UIScreen mainScreen].bounds.size.width[UIScreen mainScreen].bounds.size.height)];我现在仍然在didMoveToParent行上记录错误LogintAutorialViewController视图中有什么?看起来它有一些绘图问题。我发布的代码和你回答的代码有什么区别?你的代码行和我的代码行的顺序什么是currentClientView?那么你现在做的是:[self.view addSubview:self.view]这是错误的还是你在做[self.view addSubview:content.view]这和我的代码是一样的……你不需要这一行
    LogInTutorialViewController*lvc=[[LogInTutorialViewController alloc]init],因为您是从故事板实例化的。对于下面的错误检查答案,我相信您的顺序是不正确的。是的,我知道,但我只是尝试了一下,作为一个帖子的提示。让我感到不舒服的部分是必须明确地将原点设置为零。这个
    [self.loginView.view setFrame:self.contentView.frame]
    不能在视图中为我正确设置它,因为我的
    contentView
    有一个
    UINavigationBar
    所以
    contentView.frame.origin.y
    被按下了
    self.loginView
    。谢谢这个答案有15票以上,被接受的答案有13票以上。所以我认为这个答案一定是一个公认的答案谢谢,这个解决方案在swift 4中非常有效
    extension UIViewController {
        func addChildViewControllerWithView(_ childViewController: UIViewController, toView view: UIView? = nil) {
            let view: UIView = view ?? self.view
            childViewController.removeFromParent()
            childViewController.willMove(toParent: self)
            addChild(childViewController)
            childViewController.didMove(toParent: self)
            childViewController.view.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(childViewController.view)
            view.addConstraints([
                NSLayoutConstraint(item: childViewController.view!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
                NSLayoutConstraint(item: childViewController.view!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
            ])
            view.layoutIfNeeded()
        }
    
        func removeChildViewController(_ childViewController: UIViewController) {
            childViewController.removeFromParent()
            childViewController.willMove(toParent: nil)
            childViewController.removeFromParent()
            childViewController.didMove(toParent: nil)
            childViewController.view.removeFromSuperview()
            view.layoutIfNeeded()
        }
    }