0

I have a scrollView that contains a dynamic amount of WeatherViewControllers each displaying the weather data of a different city the user has saved. The user can segue from the WeatherViewControllers to a CityListViewController. Where they can add and remove cities from their list which in turn should add and remove WeatherViewControllers from the scrollView upon dismissing the CityListViewController, this is where I am running into a problem.

Currently I am trying to use a protocol to call viewDidLoad in the scrollViewController upon dismissing the CityListViewController but am getting an error:

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file)

when it gets to:

let weatherScreen = storyboard!.instantiateViewController(identifier: "View Controller") as! ViewController

Side Note: Upon initially opening the app the scrollView loads properly with all the correct WeatherViewControllers in the UIScrollView and the correct cities in the list.

class ScrollViewController: UIViewController, ScrollReloadProtocol {

    func reloadScrollView() {

        print("SCROLL RELOADED!!!!!*******")
        self.viewDidLoad()
    }

    @IBOutlet weak var totalScrollView: UIScrollView!
    var pages = [ViewController]()
    var x = 0
    var weatherScreensArray = [SavedCityEntity]()
    var weatherScreenStringArray = [String]()
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    var horizString = "H:|[page1(==view)]"

    let defaults = UserDefaults.standard


    override func viewDidLoad() {
        super.viewDidLoad()

        //userDefaults used to keep track of which screen is which to put different cities on different viewControllers
        defaults.set(0, forKey: "screenNumber")
        //load cities to get number of cities saved
        loadCities()

        var views : [String: UIView] = ["view": view]
        //create all weatherWeatherControllers
        while x <= weatherScreensArray.count {

            pages.append(createAndAddWeatherScreen(number: x))
            weatherScreenStringArray.append("page\(x+1)")
            views["\(weatherScreenStringArray[x])"] = pages[x].view
            let addToHoriz = "[\(weatherScreenStringArray[x])(==view)]"
            horizString.append(addToHoriz)

            x+=1
        }

        horizString.append("|")

        let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|[page1(==view)]|", options: [], metrics: nil, views: views)
        let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: horizString, options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)

        NSLayoutConstraint.activate(verticalConstraints + horizontalConstraints)
    }

    //Function to create and add weatherViewController
    func createAndAddWeatherScreen(number: Int) -> ViewController {

            defaults.set(number, forKey: "screenNumber")

            let weatherScreen = storyboard!.instantiateViewController(identifier: "View Controller") as! ViewController

            weatherScreen.view.translatesAutoresizingMaskIntoConstraints = false

            totalScrollView.addSubview(weatherScreen.view)

            addChild(weatherScreen)
            weatherScreen.didMove(toParent: self)

        return weatherScreen
    }
}
koen
  • 5,383
  • 7
  • 50
  • 89
BlakePat
  • 75
  • 7
  • What is `storyboard`, where do you load it? – koen Nov 12 '19 at 20:11
  • I'm not sure... I was following a tutorial on how to make a scrollView filled with ViewControllers and they used this function to do so. Is there another way to do this that would avoid this error? – BlakePat Nov 12 '19 at 22:05

1 Answers1

0

You could try something like this:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let weatherScreen = storyboard.instantiateViewController(withIdentifier:  "View Controller") as! ViewController

It's also probably better to use one word for the identifier: "ViewController", and give it the same name as the class. Make sure to set these values also in your actual storyboard.

koen
  • 5,383
  • 7
  • 50
  • 89
  • So this worked and made it so I progress past that line but I am now getting an error (Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file) at: totalScrollView.addSubview(weatherScreen.view) totalScreenView is nil is there a way to make it load? – BlakePat Nov 12 '19 at 23:02
  • Did you connect `totalScrollView` to the corresponding view in your storyboard? This is pretty basic stuff, see eg here: https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ConnectTheUIToCode.html – koen Nov 12 '19 at 23:09
  • like creating a IBOutlet? Yes, I did – BlakePat Nov 12 '19 at 23:26
  • If that is all set up properly, try removing `weak` where you declare the `IBOutlet`. Otherwise not sure why `totalScroillView` would be nil at that point. Try stepping through your code and see what happens – koen Nov 12 '19 at 23:35
  • I tried removing weak, no change. I have a feeling it has something to do with the fact that there is a ScrollViewController which contains WeatherViewControllers and you segue to the CityListViewController from the WeatherViewController. So maybe upon dismissing the CityListViewController, the scrollView isn't loaded for some reason? (Even though the WeatherviewControllers are inside of the scrollView) If I don't call this protocol it exists fine but does not reload the scrollView so if I add a city on the CityListViewController it is not shown. – BlakePat Nov 13 '19 at 00:21
  • Yes, that's possible. Maybe you can find some more info here on the subject here: https://stackoverflow.com/questions/29321383/iboutlet-is-nil-but-it-is-connected-in-storyboard-swift – koen Nov 13 '19 at 00:35