I'm reading a Swift OOP book and I understand the idea of instance methods having arguments which will be used within the function. What is unclear is while following online tutorials for UIPickerViews and UITableViews, there are methods that have UIPickerView or UITableView objects as parameters but aren't used in the function.
For example:
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
// Return the number of rows of data
return gamesList.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return gamesList[row].name
}
The first parameter pickerView which takes a UIPickerView object isn't used within these functions. I'm wondering why have them as parameters in the method's signature but these objects are rarely used in tutorials? Or am I thinking about this incorrectly?
Thank you in advance for any help to get a better understanding.
The first object from all the Delegate and Datasource methods that you are talking about is not unused object, it will hold the reference of the current UIPickerView, So it will used if you have multiple UIPickerView in the same ViewController. Same thing goes for all the others control like UITableView, UICollectionView etc.
For eg if you have 2 UIPickerView in the same Controller then you can fill the UIPickerView by comparing it in the UIPickerView methods.
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == firstPickerView {
return gamesList1.count
}
//else return for second pickerView
return gamesList2.count
}
So you need to compare the pickerView reference in all the methods of UIPickerView and fill or access the data according to it.
Related
I have 2 UIPickerViews in an ios program which I am running on an iPad simulator.
They have one component in each.
I find the relevant picker view by using a switch on the tag. The two single component views need to be changed by adding or deleting components.
This is easy enough in the data source with
pickerData.append(textInput)
pickerData.sort()
pickerData.reloadAllComponents
and
pickerData.remove(at: lastDataSelected)
picker.reloadAllComponents()
where lastDataSelected is the row integer.
This works to change the data source but not entirely when transferred to the UIPickerViews.
The UIPickerView display is not updated until I scroll the view. To be more precise, the item selected is correct but the text label is not updated. After scrolling the data labels are all showing correctly.
I have tried to programatically scroll from one end to the other but this does not help.
So how can I tell the program to update the view without the user scrolling it?
picker.reloadInputViews() does not help.
Apart from this the number of items (rows) isn't changed to reflect the changes in the picker data so the last item falls off the list when adding a new one.
So the second question is how to get the UIPickerView functions to update the number of rows?
I haven't been able to find any examples of dynamically updated picker views so hope someone can help or point me in the right direction.
The remaining code is fairly standard I believe but I'm obviously missing something in the update process.
override func viewDidLoad() {
super.viewDidLoad()
flvPicker = UIPickerView()
flvPicker.delegate = self
flvPicker.dataSource = self
flvPicker.tag = 0
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
switch pickerView.tag {
case 0:
return 1
case 1:
etc...
}
}
var numberOfRowsInComponent = 0
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch pickerView.tag {
case 0:
return flvPickerData.count
case 1:
etc...
}
}
func pickerView(_
pickerView: UIPickerView,
titleForRow row: Int, forComponent component: Int) -> String? {
switch pickerView.tag {
case 0:
return flvPickerData[row]
case 1:
etc...
}
}
func pickerView( _ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch pickerView.tag {
case 0:
flavourSelected = flvPickerData[row]
lastFlavourSelected = row
case 1: etc...
}
}
I think the question is really how to get the UIPickerView to update correctly after making changes to it's data source and therefore row count.
You can use reloadComponent(_:) method from UIPickerView.
A little late to the party, but if you want to update a picker view, there's also the method selectRow. This also has the benefit of an animation property, so you can animate any updates.
Example:
for (index, day) in weeklyOptions[0].enumerated() {
if scheduledTime.contains(day) {
weeklyDatePicker.selectRow(index, inComponent: 0, animated: true)
}
}
For example, in this image, when I'm scrolling the UIPickerView to 2012 9 28, what I want is that the text of the black label will change into 2012 9 28 at the same time without pressing any buttons like the Done button
I’m using UIPickerView, I can get the selected data before, I can also put the data into label by clicking a Done button, but I cannot put the data into the label when I’m scrolling.
and In a general situation,
My question is that when I Scroll the UIPickerView, how can I get the data which is selected in real time
could anyone help me ? ObjectiveC solution is OK, Swift solution is better for me, Thank you so much
It is unclear if you are using a UIPickerView or a UIDatePicker.
For UIPickerView you need to implement the UIPickerViewDelegate. Make sure that delegate is added to your ViewController declaration and make sure in Storyboard to connect the delegate of the UIPickerView control to your view controller. Then implement this function:
func pickerView(_ pickerView: UIPickerView,
didSelectRow row: Int,
inComponent component: Int) {
}
For UIDatePicker you need to connect the action of the UIDatePicker in Storyboard to an #IBAction function in your view controller or else connect it in code using the addTarget function:
myDatePicker.addTarget(self, action: #selector(self.respondToPicker, for: .valueChanged),
Let me suppose that you are using UIDatePicker, in that you can control the action using UIControlEventValueChanged
Like,
datePickerView?.addTarget(self, action: #selector(self.valueChanged(_:)), for: UIControlEvents.valueChanged)
the valueChanged() will be,
func valueChanged(_ datePicker: UIDatePicker) {
let selectedDate = datePicker.date as NSDate
print(selectedDate)
}
and if you are using UIPickerview then,
titleForRow: will gave you scrolling value
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
print("your value")
}
and didSelectRow: will give you selected value
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
print("your value")
}
I would like to know if i could get the selected String of a PickerView because when using the method func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) i only know the row selected and what i am using is if i know the row i know the position on the array i used to load the PickerViews but i wanted to do this pickerView.text to do something like this
if (pickerView.text == "hello"){
doSomething(pickerView.text);
}
Because now i have to do much more code lines to do something like this
Sorry i forget to mention, i have 3 PickerView and to know the String is in the third picker view i have to see what row is selected in each one
i only know the row selected and what i am using is if i know the row i know the position on the array
And that's the answer. Don't fight the framework; use it. The framework uses Model-View-Controller. The UIPickerView is view; it has no data. You have the data, and given the row, you can fetch it from the model.
extension UIPickerView {
func selectedTitleForComponent(component: Int) -> String? {
let row = selectedRowInComponent(component)
return dataSource.pickerView(pickerView, titleForRow:row, forComponent:component)
}
}
Then:
if pickerView.selectedTitleForComponent(0) == "hello" {
...
}
I keep getting an "'-[UITableView numberOfComponentsInPickerView:]: unrecognized selector sent to instance" error referencing a method in one of my custom UITableViewCell classes, and I can't seem to figure out why. I've searched through stack overflow but can't find an answer related to my situation. Any ideas? Thanks!
public class PickerTableViewCell:UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate {
var pickerData:[Array<Int>] = []
#IBOutlet weak var picker: UIPickerView!
public func configure(data:[Array<Int>]) {
pickerData = data
}
// Picker functions
public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return pickerData.count
}
public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData[component].count
}
public func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return String(pickerData[component][row])
}
}
If you look at the error message you see that the method numberOfComponentsInPickerView: was invoked on a UITableView instance.
So you ask the question "why would that method be invoked on a UITableView?"
The method in question is a picker view data source method, so that means that somewhere you assigned a UITableView as a picker view's data source, so that when the picker view was displayed the method call was made against a class (UITableView) that hadn't implemented the delegate method.
In your case it was a simple drag-drop error in Interface Builder.
So I have UIPickerView that isn't working the way I want it to. It works correctly about 3/4 of the time, but the other 1/4 it doesn't.
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return listsArray.count
}
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView
{
activeQuizPlace = row
var pickerLabel = UILabel()
pickerLabel.textColor = UIColor.whiteColor()
pickerLabel.text = listsArray[row]
pickerLabel.font = UIFont(name: "Georgia", size: 22)
pickerLabel.textAlignment = NSTextAlignment.Center
return pickerLabel
}
The listsArray contains 5 items(which are strings). Rows 0-2 work correctly 100% of the time. However when row 3 is selected it occasionally says that row 1 was, and when row 4 is selected it sometimes says that row 2 was. I think the problem has something to do with the last function I have that controls the UIPickerView. I just copied that code from this website as a way to change the color and font of the text. Before I was using this function I never had a problem with it, or at least never noticed one. Side note: I am using Xcode 6.3.2
I need a way for the picker view to work correctly, as well as to be able to change its font and color. I would love help with this I've been looking for answers online for 2 hours and can't figure out what I'm doing wrong, thanks in advance!
I think you need to remove the line activeQuizPlace = row from the code you have shown and then add this function below.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
activeQuizPlace = row
}
The function you were using is not called with the index that the user selects, it is called with the index that the system needs for drawing the views.
The suggested function should be the one you are after (hopefully).