I have 2 UIPickerViews in my ViewController. Each picker view has a separate swift file which acts as the picker's datasource and delegate. I want the number of rows in the second pickerView to depend on the row selected in the first pickerView. When I try to implement this in the "didSelect" function of the first pickerView I get an error: "unexpectedly found nil while unwrapping an Optional value"
Here's my code:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
@IBOutlet var bookPickerView: UIPickerView!
@IBOutlet var chapterPickerView: UIPickerView!
var booksClass: BooksClass!
var chaptersClass: ChaptersClass!
override func viewDidLoad() {
super.viewDidLoad()
booksClass = BooksClass()
chaptersClass = ChaptersClass()
bookPickerView.delegate = booksClass
bookPickerView.dataSource = booksClass
chapterPickerView.delegate = chaptersClass
chapterPickerView.dataSource = chaptersClass
chaptersClass.chaptersList = chaptersClass.chaptersList0
}
}
ChaptersClass.swift:
import UIKit
class ChaptersClass: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
var chaptersList: [String]!
func numberOfComponents(in: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return chaptersList.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return chaptersList[row]
}
//Number of chapters for each book:
var chaptersList0: [String]! = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37"]
var chaptersList1: [String]! = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25"]
var chaptersList2: [String]! = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27"]
}
BooksClass.swift:
import UIKit
class BooksClass: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
var viewController: ViewController!
var chaptersClass: ChaptersClass!
var booksList: [String]! = ["Jenesis", "Exodus", "Livitikōs"]
func numberOfComponents(in: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return booksList.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return booksList[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
chaptersClass = ChaptersClass()
viewController = ViewController()
switch row {
case 0:
chaptersClass.chaptersList = chaptersClass.chaptersList0
case 1:
chaptersClass.chaptersList = chaptersClass.chaptersList1
case 2:
chaptersClass.chaptersList = chaptersClass.chaptersList2
default:
return
}
viewController.chapterPickerView.reloadAllComponents()
}
}
The error occurs in the following line of my BooksClass.swift file:
viewController.chapterPickerView.reloadAllComponents()
UPDATE: @Sanchit Kumar Singh
I have updated my code with help from Sanchit's suggestion. I am currently not getting any errors, but the "chapters" pickerView is still not being updated for some reason. Can anyone point out what I'm doing wrong?
NOTE: I modified the "ViewController.swift" and "BooksClass.swift" files. The new entries in my code are surrounded by ** asterisks **.
ViewController.swift:
import UIKit
class ViewController: UIViewController, **BooksClassDelegate** {
@IBOutlet var bookPickerView: UIPickerView!
@IBOutlet var chapterPickerView: UIPickerView!
var booksClass: BooksClass!
var chaptersClass: ChaptersClass!
**func updateChaptersList() {**
**self.chapterPickerView.reloadAllComponents()**
**}**
override func viewDidLoad() {
super.viewDidLoad()
booksClass = BooksClass()
chaptersClass = ChaptersClass()
bookPickerView.delegate = booksClass
bookPickerView.dataSource = booksClass
chapterPickerView.delegate = chaptersClass
chapterPickerView.dataSource = chaptersClass
chaptersClass.chaptersList = chaptersClass.chaptersList0
**booksClass.referenceToViewController = self**
}
}
BooksClass.swift:
import UIKit
**protocol BooksClassDelegate {**
**func updateChaptersList()**
**}**
class BooksClass: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
var viewController: ViewController!
var chaptersClass: ChaptersClass!
**var referenceToViewController: BooksClassDelegate?**
var booksList: [String]! = ["Jenesis", "Exodus", "Livitikōs"]
func numberOfComponents(in: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return booksList.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return booksList[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
chaptersClass = ChaptersClass()
switch row {
case 0:
chaptersClass.chaptersList = chaptersClass.chaptersList0
case 1:
chaptersClass.chaptersList = chaptersClass.chaptersList1
case 2:
chaptersClass.chaptersList = chaptersClass.chaptersList2
default:
return
}
**referenceToViewController?.updateChaptersList()**
}
}
The only problem I see in your didSelectRow function i.e.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
chaptersClass = ChaptersClass()
**viewController = ViewController()**
switch row {
case 0:
chaptersClass.chaptersList = chaptersClass.chaptersList0
case 1:
chaptersClass.chaptersList = chaptersClass.chaptersList1
case 2:
chaptersClass.chaptersList = chaptersClass.chaptersList2
default:
return
}
viewController.chapterPickerView.reloadAllComponents()
}
is, Why are you initialising a new ViewController. See, the main problem is you have just initialised the ViewController class, but haven't added it to your view hierarchy so ViewDidLoad is never called, which will further leads to chaptersList in chaptersClass to nil, because it was never set.
I think you want to use same viewcontroller instance which is already present in your view hierarchy, for that you need to use delegate or some other means to inform your viewcontroller instance which is already present there. I am leaving this part up to you. I think this will solve your problem.