1

I want to pass string data from parent vc to child vc in swift 3.
My child vc is container view. So watch my code:

class ParentViewController: UIViewController
@IBOutlet var continerView: UIView!
override func viewDidLoad() {
        super.viewDidLoad()
let vc = storyboard?.instantiateViewController(withIdentifier: "ChildVCID") as! ChildViewController!
        vc?.myStr = "Hello Bro"
        addChildViewController(vc!)
        continerView.addSubview((vc?.view)!)
        didMove(toParentViewController: vc)
}
}  

And my child code is:

class ChildViewController: UIViewController
 var myStr:String!
override func viewDidLoad() {
        super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
        print("Str is: ",myStr)
    }

So this error will show:
enter image description here

Therefore how to fix this?

shallowThought
  • 19,212
  • 9
  • 65
  • 112
reza_khalafi
  • 6,230
  • 7
  • 56
  • 82
  • can you attach your project – Anbu.Karthik Jan 31 '17 at 06:36
  • 1
    please go step by step, like just dont pass data directly, try first to load view(add subview). If its successful , then pass data, try modification in code var myStr:String! to var myStr:String?. I am sure your code is correct , only you are missing something with optionals. – ViJay Avhad Jan 31 '17 at 06:45
  • 1
    Please format your code properly. At least check that it's properly set up. There are a lot of issues I can identify. Neither of classes has an opening bracket, call to super.viewDidAppear not there, code alignment, spaces between functions, force unwrapping is evil... etc – Oleg Danu Jan 31 '17 at 06:47
  • @OlegDanu correct bro. Its just optional binding where he messed. i tried piece of code from ChildViewController, change var myStr:String! to var myStr:String? , your app will not crash. – ViJay Avhad Jan 31 '17 at 06:51
  • 1
    I suggest adding `super.viewDidAppear(animated)` as the first line of ChildViewController viewDidAppear. I don't think this is causing the crash though. – Mobile Dan Jan 31 '17 at 06:52
  • I tried same code to replicate the issue, but it worked fine. – Amit Tandel Jan 31 '17 at 06:53
  • 1
    Try adding super.viewDidAppear(animated) in childVCs viewDidAppear, ass suggested by @MobileDan – Amit Tandel Jan 31 '17 at 06:54
  • 2
    I think `didMove(toParentViewController: vc)` should be `didMove(toParentViewController: self)` – Mobile Dan Jan 31 '17 at 06:59

2 Answers2

3

This code incorporates suggestions made in comments and does not use force unwrapping.

class ParentViewController: UIViewController {
    @IBOutlet var continerView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let childViewController = storyboard?.instantiateViewController(withIdentifier: "ChildVCID") as? ChildViewController else {
            print("Creating ViewController from ChildVCID failed")
            return
        }

        childViewController.myStr = "Hello Bro!"
        addChildViewController(childViewController)
        continerView.addSubview(childViewController.view)
        didMove(toParentViewController: self)

    }
}

class ChildViewController: UIViewController {
    var myStr:String?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("Str is: ", myStr ?? "(nil)")
    }
}
Mobile Dan
  • 6,444
  • 1
  • 44
  • 44
0

Whatever is written in question is correct, all are just missing one main thing where storyboards comes in focus, as ChildViewController in storyboard is already embeded in ContainerView with embed seague, which automatically loads this vc to container, and app crashed beacause 'myStr' was force unwrapped while is nil,

I have written ParentViewController, minimal '!' & '?', why to use them while they are unnecessary.

 class ParentViewController: UIViewController{
    @IBOutlet var cv: UIView!
    override func viewDidLoad() {
     super.viewDidLoad()
     let storyBoard = UIStoryboard(name: "Main", bundle: nil)
     let vc = storyBoard.instantiateViewController(withIdentifier: "idChildViewController") as! ChildViewController
     vc.myStr = "Hello Bro"
     addChildViewController(vc)
     cv.addSubview(vc.view)
     didMove(toParentViewController: vc)
    }
   }
 }

Now, in ChildViewController, why to declare varible as not optional,

  class ChildViewController: UIViewController
   var myStr:String?  // or var myStr = "" //best way to declare string 
   override func viewDidLoad() {
       super.viewDidLoad()
   }
   override func viewDidAppear(_ animated: Bool) {
      print("Str is: ",myStr)
   }

Run the app, will give console output twice as ,

Str is: nil //loaded from storyboard

Str is: Optional("Hello Bro") // loaded from parent

ViJay Avhad
  • 2,684
  • 22
  • 26