2

I m trying to add child view controller to a containerViewController

Child are :

AViewController
BViewController
CViewController

I have no error but when i launch the app, i can swipe the screen, there is 3 section swiped but the A,B,C view controllers don't appeared..

This is my code, any idea ?

import UIKit

class ContainerViewController: UIViewController {

@IBOutlet var scrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    // creat VC

    var Avc : AViewController = AViewController ()
    var Bvc : BViewController = BViewController ()
    var Cvc : CViewController = CViewController ()



    // add it to the view hierarchie


    self.addChildViewController(Cvc)
    self.scrollView.addSubview(Cvc.view)
    Cvc.didMoveToParentViewController(self)

    self.addChildViewController(Bvc)
    self.scrollView.addSubview(Bvc.view)
    Bvc.didMoveToParentViewController(self)


    self.addChildViewController(Avc)
    self.scrollView.addSubview(Avc.view)
    Avc.didMoveToParentViewController(self)

    // set the frame

    var adminFrame : CGRect = Avc.view.frame
    adminFrame.origin.x = adminFrame.width
    Bvc.view.frame = adminFrame

    var BFrame : CGRect = Bvc.view.frame
    BFrame.origin.x = 2*BFrame.width
    Cvc.view.frame = BFrame

    // set the frame of the scrollview


    var scrollWidth: CGFloat = 3*self.view.frame.width
    var scrollHeight: CGFloat = self.view.frame.size.height
    self.scrollView.contentSize = CGSizeMake(scrollWidth, scrollHeight)


}

Edit:

Looking at the view hierarchy, it reports the following:

<UIWindow: 0x7ff3fad19f70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7ff3fac3efe0>; layer = <UIWindowLayer: 0x7ff3fad19740>>
   | <UIView: 0x7ff3fb108b90; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fb108e60>>
   |    | <UIScrollView: 0x7ff3fac3acf0; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7ff3fb107320>; layer = <CALayer: 0x7ff3fac18e00>; contentOffset: {0, 0}; contentSize: {960, 568}>
   |    |    | <UIView: 0x7ff3fac41ed0; frame = (640 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac28a00>>
   |    |    | <UIView: 0x7ff3fac42320; frame = (320 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac38e10>>
   |    |    | <UIView: 0x7ff3fac42730; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac42810>>
   |    |    | <UIImageView: 0x7ff3faf020f0; frame = (0 564.5; 320 3.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x7ff3fae0df80>>
   |    |    | <UIImageView: 0x7ff3fac1c660; frame = (316.5 0; 3.5 568); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x7ff3fac39420>>
   |    | <_UILayoutGuide: 0x7ff3fb108ec0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7ff3fb1091e0>>
   |    | <_UILayoutGuide: 0x7ff3fb109c20; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x7ff3fb109d00>>
7
  • You might want to pause the app and at the (lldb) prompt, enter po [[UIWindow keyWindow] recursiveDescription], which will show you the frames for all of the views. It seems to me that you never set Avc.view.frame, so I bet its CGRectZero. I'd suggest Avc.view.frame = self.view.bounds before you start setting the frame of Bvc and Cvc. Commented Aug 20, 2014 at 12:27
  • I think the only frame witch is dysplayed is the scrollView's frame of my container, i tried your solution but it doesn't work. Commented Aug 20, 2014 at 13:44
  • The (lldb) po [[UIWindow keyWindow] recursiveDescription] <UIWindow: 0x7ffbd9454b20; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7ffbd94553d0>; layer = <UIWindowLayer: 0x7ffbd9451c00>> | <UIView: 0x7ffbd9718e60; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ffbd9719130>> | | <UIScrollView: 0x7ffbd970fdd0; frame = (0 0; 320 568); Commented Aug 20, 2014 at 13:49
  • Brilliant! So your subviews are there! But you haven't apparently added anything to those subviews, so there's nothing to see. Commented Aug 20, 2014 at 20:45
  • I just changed the color's background for each of them to identify the different subviews, but i can't see the different color when swipping, everything is white. I also add a label... Commented Aug 20, 2014 at 20:48

2 Answers 2

7

Use following Extension for adding ChildviewController create file Extensions.swift copy bellow code

import UIKit

extension UIViewController {
    func configureChildViewController(childController: UIViewController, onView: UIView?) {
        var holderView = self.view
        if let onView = onView {
            holderView = onView
        }
        addChildViewController(childController)
        holderView?.addSubview(childController.view)
        constrainViewEqual(holderView: holderView!, view: childController.view)
        childController.didMove(toParentViewController: self)
    }


    func constrainViewEqual(holderView: UIView, view: UIView) {
        view.translatesAutoresizingMaskIntoConstraints = false
        //pin 100 points from the top of the super
        let pinTop = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal,
                                    toItem: holderView, attribute: .top, multiplier: 1.0, constant: 0)
        let pinBottom = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal,
                                       toItem: holderView, attribute: .bottom, multiplier: 1.0, constant: 0)
        let pinLeft = NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal,
                                     toItem: holderView, attribute: .left, multiplier: 1.0, constant: 0)
        let pinRight = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal,
                                      toItem: holderView, attribute: .right, multiplier: 1.0, constant: 0)

        holderView.addConstraints([pinTop, pinBottom, pinLeft, pinRight])
    }
}

User view controller

    import UIKit

    class MyViewControler:UIViewControler  {

    @IBOutlet weak var myView: UIView!



    override func viewDidLoad() {
        super.viewDidLoad()

        let demoViewInstance = storyboard!.instantiateViewController(withIdentifier: "youChiledViewController_Id") as! childViewController
        configureChildViewController(childController: demoViewInstance, onView: myView)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
Sign up to request clarification or add additional context in comments.

3 Comments

I find your answer a bit unclear - where do the contstraints come in? Could you clarify a bit what your extension intends to do and why you sugest this approach? It would help me understand how to approach this.
@NataliaChodelski please check above updated code for better understand
@PhaniSai I have reworked your code slightly, so there is no explicit unwrapping holderView!. gist.github.com/neoneye/fd01d21944b40fc7794af6c8f0591725
3

When I use your code, run the app, and pause the app, and look at the view hierarchy, I see the following:

(lldb) po [[UIWindow keyWindow] recursiveDescription]
<UIWindow: 0x156bdc30; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x156be750>; layer = <UIWindowLayer: 0x156aa3c0>>
   | <UIView: 0x156c5440; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x156c55c0>>
   |    | <UIScrollView: 0x156c2740; frame = (0 0; 0 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x156c4d00>; layer = <CALayer: 0x156c2a80>; contentOffset: {0, 0}; contentSize: {960, 568}>
   |    |    | <UIView: 0x156c6df0; frame = (640 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c6d80>>
   |    |    | <UIView: 0x156c7100; frame = (320 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c70a0>>
   |    |    | <UIView: 0x156c73f0; frame = (0 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c7390>>
   |    |    | <UIImageView: 0x156c8bd0; frame = (0 564.5; 600 3.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x156c8c50>>
   |    |    | <UIImageView: 0x156c9020; frame = (-3.5 32; 3.5 568); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x156c90a0>>
   |    | <_UILayoutGuide: 0x156c5620; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x156c5800>>
   |    | <_UILayoutGuide: 0x156c5c90; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x156c5d10>>

If you're not seeing your subviews there, then likely culprits include:

  • You may not have specified the view controller base class in your scene, and thus this code isn't being run. You can confirm this with a println log statement or breakpoint in side this viewDidLoad and make sure you're hitting this routine.

  • You may not have hooked up the @IBOutlet for the scrollView, and thus scrollView is nil. Confirm this by putting breakpoint in viewDidLoad and examining the scrollView property.


In your revised question, we can now see that the three subviews are present and appear to be the correct size. That's great.

Now the question is why you don't see anything. If you have these defined as scenes in your storyboard, you should:

  • Make sure the "base class" and the "storyboard identifier" is defined for each of these three child scenes; and

  • When your main view controller instantiates the three child view controllers, you would instantiate them from the storyboard using the storyboard identifier (in my example, I used storyboard identifiers of A, B, and C, respectively):

    let Avc = storyboard.instantiateViewControllerWithIdentifier("A") as AViewController
    let Bvc = storyboard.instantiateViewControllerWithIdentifier("B") as BViewController
    let Cvc = storyboard.instantiateViewControllerWithIdentifier("C") as CViewController
    

If you do the above and repeat the recursiveDescription you should see your scene's subviews (e.g. the labels you added) appear in the output.

7 Comments

So, when you put your breakpoint in viewDidLoad, and examined scrollView when you hit the breakpoint, it was non-nil?
i ve got an error in this breakpoint with po [[UIWindo keyWindow] recursiveDescription] :error: <EXPR>:1:12: error: expected ',' separator [[UIWindow keyWindow] recursiveDescription] ^ , <EXPR>:1:23: error: expected ',' separator [[UIWindow keyWindow] recursiveDescription]
sorry im noob...i have this <UIScrollView: 0x7fd47ac17540; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fd47ac1ea90>; layer = <CALayer: 0x7fd47ac16ac0>; contentOffset: {0, 0}; contentSize: {0, 0}>
Ok i tried to instantiate from the storyboard but the ap crash because "doesn't contain a view controller with identifier 'A'". It s normal since i can't set the "A" identifier in the storyboard. In my storyboard i have only one view controler (ContainerViewControler class). A, B, CViewController are xib file so they are not visible ine the storyboard. Thank for your patience and sorry for my bad english..
It's weird to use a NIB rather than putting it on your storyboard, but that's fine. If it's in a NIB, you have to instantiate your view controller from that (e.g. let Avc = AViewController(nibName: "nibname", bundle: nil)).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.