I have a picker with two options currently, and what I am looking for is, based on the selection made in the picker, to determine the next viewController below is what I tried to use however, I immediately got an error stating the last "if" statement should be converted into a let statement. Below is the code for my picker and attempt to lead into associated segue.
import UIKit
import Firebase
import CoreData
import CoreLocation
class SchoolPickerViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var SchoolPicker: UIPickerView!
let pickerData = ["Ohio State University", "University of Rochester"]
override func viewDidLoad() {
super.viewDidLoad()
SchoolPicker.dataSource = self
SchoolPicker.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
#IBAction func schoolSelectorGoButton(sender: AnyObject) {
if pickerData = "Ohio State University" {
performSegueWithIdentifier("ohioStateSelected", sender: sender)
}
if pickerData = "University of Rochester" {
performSegueWithIdentifier("rochesterSelected", sender: sender)
}
}
}
u should get selected picker data from Array
define
var selectedIndex = 0
then in this line
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
selectedIndex = row
return pickerData[row]
}
and in this action
#IBAction func schoolSelectorGoButton(sender: AnyObject) {
if pickerData[selectedIndex] == "Ohio State University" {
performSegueWithIdentifier("ohioStateSelected", sender: sender)
}
}
Related
In my searches, I see this is a common question but I've tried some of the solutions and haven't been able to resolve. A simple example below. When I run the app, and press button, 0 prints as expected. After pressing button2, then button, 1 prints, also as expected. If I move the picker, then press button, I expect 2, but still get 1.
I gather this is because ViewController().sample() is creating a copy, and not actually changing the variable in the "original" ViewController(). I'm stumped at what needs to be reconfigured to get the desired behavior.
import UIKit
class pickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
ViewController().sample()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
var test = Int()
#IBAction func button(_ sender: Any) {
print(test)
}
#IBAction func button2(_ sender: Any) {
test = 1
}
func sample() {
test = 2
}
}
This is a situation where you would either use a delegation pattern or a callback closure; this latter is more "Swifty".
With delegation:
protocol PickerHelperDelegate {
func pickerHelper(_ helper: selectedRow row:)
}
Then in your PickerHelper you add a delegate property and invoke the delegate when required:
class PickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
var delegate: PickerHelperDelegate?
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.delegate?.pickerHelper(self, selectedRow: row)
}
}
In your view controller you need to assign the delegate and implement the protocol function:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
helper1.delegate = self // Assign this object as the picker helper's delegate
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
var test = Int()
}
extension ViewController: PickerHelperDelegate {
func pickerHelper(_ helper: PickerHelper, selectedRow row:Int) {
self.sample()
print("Selected row \(row)")
}
}
You can do a similar thing with a closure:
class PickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
var changeHandler: ((Int)->Void)?
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.changeHandler?(row)
}
}
In your view controller you need to assign a closure to the changeHandler property:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
helper.changeHandler = { row in
self.sample()
print("Selected row \(row)")
}
}
You could also change your protocol or closure to pass back the data element rather than just the row number and use generics for your PickerHelper so that it wasn't just limited to strings.
Note that classes start with a capital by convention, so you should say PickerHelper, not pickerHelper.
You can use the static property to keep its state in class.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
static var test = Int()
#IBAction func button(_ sender: Any) {
print(test)
}
#IBAction func button2(_ sender: Any) {
ViewController.test = 1
}
static func sample() {
test = 2
}
}
I have a picker set up and want to have the user make a selection then tap a button which leads to a url. This is what I have so far:-
class PickerViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var picker: UIPickerView!
#IBOutlet weak var label: UILabel!
var url = NSURL(string: "http://www.google.com")
var pickerData: [String] = [String]()
var pickerSites: [String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.picker.delegate = self
self.picker.delegate = self
pickerData = ["Google", "Facebook"]
pickerSites = ["http://www.google.com", "http://www.facebook.com"]
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
label.text = pickerSites[row]
}
siteBtn.addTarget(self, action: "didTapSite", forControlEvents: .TouchUpInside)
#IBAction func sitesBtn(sender: AnyObject) {
UIApplication.shared().openURL(NSURL(string: "http://www.google.com")!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I've connected the "siteBtn" to a button on the screen. The picker and text label were working fine until I added the code for the button. I'm not sure if I've put the button code in the correct place. I know that I need the button to connect with the picker "didSelectRow" and that the "pickerData" list needs to correlate to the "pickerSites" list but I'm stuck.
Any help would be much appreciated.
this is the minimal setup you need. feel free to ask if anything is unclear:
// outlet to the pickerview
#IBOutlet weak var picker: UIPickerView!
// datasource
let pickerData = ["Google", "Facebook"]
let pickerSites = ["http://www.google.com", "http://www.facebook.com"]
// pickerview datasource methods
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
// pickerview delegate method
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
// ibaction for button tap
#IBAction func goToURLButtonTapped(sender: UIButton) {
let selectedSite = pickerSites[picker.selectedRowInComponent(0)]
UIApplication.sharedApplication().openURL(NSURL(string: selectedSite)!)
}
How to navigate between two viewcontrollers using a UIPickerview
I am trying to navigate between two viewcontrollers using a UIPickerview, so i first learned how to use didSelectRow to change the title of a label and then i tried using some code to navigate to another viewcontroller but that didn't work.
The code that i used was:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet var label: UILabel!
#IBOutlet var pickerView: UIPickerView!
var food = ["hello", "hi", "hey"]
var placementAnswer = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
pickerView.delegate = self
pickerView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return food.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return food[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
placementAnswer = row
}
#IBAction func labelChanged(sender: UIButton) {
if (placementAnswer == 0){
}else if (placementAnswer == 1){
let view2 =
self.storyboard?.instantiateViewControllerWithIdentifier("view2") as! ViewController2
self.navigationController?.pushViewController(view2, animated: true)
}else if (placementAnswer == 2){
}
}
}
I am trying to navigate between two viewcontrollers using a UIPickerview, so i first learned how to use didSelectRow to change the title of a label and then i tried using some code to navigate to another viewcontroller but that didn't work.
The code that i used was:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet var label: UILabel!
#IBOutlet var pickerView: UIPickerView!
var food = ["hello", "hi", "hey"]
var placementAnswer = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
pickerView.delegate = self
pickerView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return food.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return food[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
placementAnswer = row
}
#IBAction func labelChanged(sender: UIButton) {
if (placementAnswer == 0){
}else if (placementAnswer == 1){
let view2 = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as! ViewController2
self.navigationController?.pushViewController(view2, animated: true)
}else if (placementAnswer == 2){
}
}
}
As paranoidcoder pointed out I'm not sure your labelChanged method is getting called, which could be the problem with your existing code.
I'm assuming you want to change the view controller after a certain row is selected in the picker view. Putting the if statement to change views in didSelectRow would make the most sense in that case.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
placementAnswer = row // unnecessary variable
if (placementAnswer == 0){}
else if (placementAnswer == 1)
{
let view2 = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as! ViewController2
self.navigationController?.pushViewController(view2, animated: true)
}
else if (placementAnswer == 2) {}
}
After pulling an app that was built using Swift 6 to now a system that is using 6 beta, I'm getting an "EventFormViewController does not conform to protocol UIPickerViewDataSource". I have struggled with this for several days now, any suggestions?
import UIKit
var eventChoices = [
["5","10","15","30","45","60","90","120","150","180"],
["Hospital Committee","Peer Review","EHR Improvement","Quality Improvement","Business Development"], ]
class EventFormViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate{
#IBOutlet weak var eventPicker: UIPickerView!
#IBOutlet weak var eventLabel: UILabel!
#IBOutlet weak var commentField: UITextField!
func updateLabel(){
let selectedTime = eventChoices[0][eventPicker.selectedRowInComponent(0)]
let event = eventChoices[1][eventPicker.selectedRowInComponent(1)]
eventLabel.text = "Chose \(event) for \(selectedTime) mins"
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
updateLabel() }
override func viewDidLoad() {
super.viewDidLoad()
}
// Do any additional setup after loading the view.
}
func didReceiveMemoryWarning() {
didReceiveMemoryWarning() // Dispose of any resources that can be recreated.
}
// returns the number of 'columns' to display. func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return eventChoices.count }
// returns the # of rows in each component..
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
return eventChoices[component].count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return eventChoices[component][row] }
func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
if (component == 0) {
return 50.0;
}
return 300.0;
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
There are alot of issues in your code.
1
The function header is commented.
// returns the number of 'columns' to display. func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return eventChoices.count }
It should be like:
// returns the number of 'columns' to display.
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{
return eventChoices.count
}
2
You are closing your class definition right after the viewDidLoad implementation.
It should be like:
import UIKit
var eventChoices = [
["5","10","15","30","45","60","90","120","150","180"],
["Hospital Committee","Peer Review","EHR Improvement","Quality Improvement","Business Development"], ]
class EventFormViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate
{
#IBOutlet weak var eventPicker: UIPickerView!
#IBOutlet weak var eventLabel: UILabel!
#IBOutlet weak var commentField: UITextField!
func updateLabel()
{
let selectedTime = eventChoices[0][eventPicker.selectedRowInComponent(0)]
let event = eventChoices[1][eventPicker.selectedRowInComponent(1)]
eventLabel.text = "Chose \(event) for \(selectedTime) mins"
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
updateLabel()
}
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated.
}
// returns the number of 'columns' to display.
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{
return eventChoices.count
}
// returns the # of rows in each component..
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
return eventChoices[component].count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String!
{
return eventChoices[component][row]
}
func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat
{
var width = 300.0
if (component == 0)
{
width = 50.0;
}
return width;
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You've got some typing-errors:
Before your didReceiveMemoryWarning you've got a close bracket which closes the class. So your other methods aren't in the class with the UIPickerViewDelegate and so the delegate thinks, that the methods doesn't exist.
So move the bracket to the end of your code to close the class.
Secondly, you've got a mistake after the didReceiveMemoryWarning method. You've got outcommented a method header:
// returns the number of 'columns' to display. func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return eventChoices.count }
So change that to look like that:
// returns the number of 'columns' to display.
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return eventChoices.count
}
And last but not least you need to override the didReceiveMemoryWarning method. So change that:
func didReceiveMemoryWarning() {
didReceiveMemoryWarning() // Dispose of any resources that can be recreated.
}
to that:
override func didReceiveMemoryWarning() {
didReceiveMemoryWarning() // Dispose of any resources that can be recreated.
}