1

I am building a running app and am trying to programmatically present a view controller when the start run button is tapped. However, when I tap the button after setting up the presenting view controller, any reference to an IBOutlet is found nil when unwrapping in the order that they are called.

It's worth noting that when I connect the two view controllers with "show" via storyboard instead, that everything works fine, but I want to present the view controller programmatically and in fullscreen rather than the cardlike presentation by default.

From the presenting view controller:

@IBAction func startRunTapped(_ sender: Any) {
    let inRunVC = CurrentRunVC()
    inRunVC.modalPresentationStyle = .fullScreen
    self.present(inRunVC, animated: true, completion: nil)
}

From the presented view controller:

import UIKit
import MapKit

class CurrentRunVC: LocationVC {


@IBOutlet weak var sliderImageView: UIImageView!
@IBOutlet weak var swipeBGImageView: UIImageView!
@IBOutlet weak var durationLabel: UILabel!
@IBOutlet weak var paceLabel: UILabel!
@IBOutlet weak var distanceLabel: UILabel!
@IBOutlet weak var pauseButton: UIButton!

var startLocation: CLLocation!
var lastLocation: CLLocation!
var timer = Timer()

var runDistance = 0.0
var pace = 0
var counter = 0

override func viewDidLoad() {
    super.viewDidLoad()
    let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(endRunSwiped(sender:)))
    sliderImageView.addGestureRecognizer(swipeGesture) //error unwrapping here
    sliderImageView.isUserInteractionEnabled = true    // and here
    swipeGesture.delegate = self as? UIGestureRecognizerDelegate
} 

//errors also on any other reference to an IBOutlet

I've confirmed that all IBOutlets are connected properly.

Storyboard:

enter image description here

Thanks in advance

jade
  • 33
  • 3
  • You aren't initializing the ViewController connecting it with its Storyboard version. You need to use `UIStoryboard(name: "storyboardName", bundle: nil).instantiateViewControllerWithIdentifier("CurrentRunVC")` as! CurrentRunVC` – Larme Jan 08 '21 at 15:43
  • But with Storyboard, you could have chosen "Present Modally" instead of "Show", then "Presentation": "Full Screen" – Larme Jan 08 '21 at 15:46

2 Answers2

1

You are not grabbing the correct storyboard instance of CurrentVC but you are creating a new one. Instead of let inRunVC = CurrentRunVC(), use

let runVC = self.storyboard?.instantiateViewController(withIdentifier: "CurrentRunVC") as! CurrentRunVC //set the identifier in the storyboard identity inspector
Luca Sfragara
  • 624
  • 4
  • 16
0

Your view controller's outlets are defined in the storyboard, and created when the view controller is loaded from the storyboard. When you just initialise a new view controller in this line:

let inRunVC = CurrentRunVC()

Then the system will look for a xib file with the same name as the view controller, which doesn't exist, which means it just loads a blank view with no connected outlets. All those implicitly unwrapped optionals are now nil.

Either make a new segue from the button to the same view controller, but a modal presentation, or add a reference to the presented view controller in the storyboard and then load it using the instatiate with identifier method of the current storyboard.

jrturton
  • 118,105
  • 32
  • 252
  • 268