I've created a view using Interface Builder as a xib. I've done this as I want to give the user the option to increment any number of these views to the view controller. I've created an Xib view (named "TimeRangeView.xib", created a custom class (named "TimeRangeView.swift") and set the xib's class to this custom class, connected the storyboard elements to the TimeRangeView.swift's IBOutlets, set the xib's file owner to TimeRangeView.swift, and added the view with its class set to my TimeRangeView.swift in the view controller.
TimeRangeView.swift:
import UIKit
class TimeRangeView: UIView {
@IBOutlet var startTimeLabel: UILabel!
@IBOutlet var startDatePicker: UITextField!
@IBOutlet var endTime: UILabel!
@IBOutlet var endDatePicker: UITextField!
@IBOutlet var addButton: UIButton!
@IBOutlet var maxTimeLabel: UILabel!
@IBAction func addButtonPressed(_ sender: UIButton) {
}
}
The storyboard UIViewController I am using this in has an Interface Builder view as a subview; this view's class is assigned as TimeRangeView.swift. This view is connected to the view controller as an IBOutlet:
@IBOutlet var timeRangeView: TimeRangeView!
Within the view controller's viewDidLoad() method, I am wanting to change some of TimeRangeView's subviews (which, as we've covered, are connected as IBOutlets), but they are returning nil when I try to change some of their properties:
override func viewDidLoad() {
super.viewDidLoad()
timeRangeView.maxTimeLabel.text = "Max duration: \(timeString ?? "n/a")"
//Change the text fields' input views
let startTimeDatePickerToolBar = UIToolbar().ToolbarPicker(mySelect: #selector(dismissPicker))
let endTimeDatePickerToolBar = UIToolbar().ToolbarPicker(mySelect: #selector(dismissPicker))
startTimeDatePicker.setDate(Date(timeIntervalSince1970: NSDate().timeIntervalSince1970 + 60), animated: false)
endTimeDatePicker.setDate(Date(timeIntervalSince1970: NSDate().timeIntervalSince1970 + 120), animated: false)
timeRangeView.startDatePicker.inputView = startTimeDatePicker
timeRangeView.startDatePicker.inputAccessoryView = startTimeDatePickerToolBar
timeRangeView.startDatePicker.delegate = self
timeRangeView.endDatePicker.inputView = endTimeDatePicker
timeRangeView.endDatePicker.inputAccessoryView = endTimeDatePickerToolBar
timeRangeView.endDatePicker.delegate = self
}
timeRangeView is not returning nil; it is loading. But when trying to access timeRangeView's subviews (startDatePicker, endDatePicker, maxTimeLabel), they are all returning nil.
The error I am receiving is:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
This is happening Because the xib was never loaded
So what you can do here is, First add a simple UIView
in the viewController rather than TimeRangeView
@IBOutlet var timeRangeContainerView: UIView!
Now in viewDidLoad
add Fetch the xib
by using
let timeRangeView = Bundle.main.loadNibNamed("TimeRangeView", owner: self, options: nil)?[0] as? TimeRangeView
And add this as a subview of timeRangeContainerView
override func viewDidLoad() {
super.viewDidLoad()
let timeRangeView = Bundle.main.loadNibNamed("TimeRangeView", owner: self, options: nil)?[0] as? TimeRangeView
timeRangeView.frame = CGRect(origin: CGPoint.zero, size: self.timeRangeContainerView.frame.size)
self.timeRangeContainerView.insertSubview(timeRangeView, at: 0)
// Add constraints
timeRangeView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
timeRangeView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
timeRangeView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
timeRangeView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
timeRangeView.translatesAutoresizingMaskIntoConstraints = false
//Add the rest of your code here
}
The constraints are optional