Pass chose value into label inside a table view cell - swift

I'm relatively new into swift and I'm still struggling with some basics. But well thank you all fo helping me in this. Ok when a UITableViewCellis selected a PopUpViewController is presented with a datepicker so the user can select a desire date and when dissmisButtonis pressed the current view is dismissed and as soon that happens I want the selected value to show on the label embedded on the selected UITableViewCell.
Code on PopUpViewController
import UIKit
class PopUpColchonesViewController: UIViewController {
var tipoColchonArray = [String](arrayLiteral: "Individual", "Matrimonial", "King Size")
#IBOutlet weak var tipoColchonLb: UILabel!
#IBOutlet weak var tipoColchonPicker: UIPickerView!
#IBOutlet weak var guardarTipoColchon: UIButton!
var tipoSeleccionado : String?
override func viewDidLoad() {
super.viewDidLoad()
tipoColchonPicker.delegate = self
tipoColchonPicker.dataSource = self
// Do any additional setup after loading the view.
}
#IBAction func guardarTipo(_ sender: Any) {
NotificationCenter.default.post(name: .guardarTipo, object: nil)
dismiss(animated: true, completion: nil)
}
}
extension PopUpColchonesViewController : UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return tipoColchonArray.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return tipoColchonArray[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let selectedItem = tipoColchonArray[row]
tipoSeleccionado = selectedItem
}
}
extension Notification.Name {
static let guardarTipo = Notification.Name(rawValue: "guardarTipo")
}
What I've try so far
var observer : NSObjectProtocol?
var cellServicio = UITableViewCell()
override func viewDidLoad() {
super.viewDidLoad()
servicioHogarTB1.delegate = self
servicioHogarTB1.dataSource = self
servicioHogarTB1.register(UINib(nibName: "ServicioCell", bundle: nil), forCellReuseIdentifier: "servicioCell")
servicioHogarTB1.separatorStyle = .none
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(handlePopupClosing), name: .guardarTipo, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let observer = observer {
NotificationCenter.default.removeObserver(observer)
}
print(servicioSeleccionado)
}
#objc func handlePopupClosing (notification : NSNotification) {
let tipoVC = notification.object as? PopUpColchonesViewController
let index = servicioHogarTB1.indexPathForSelectedRow
if let cell = servicioHogarTB1.cellForRow(at: index!) as? ServicioCell {
cell.servicioTipoLb.text = tipoVC?.tipoSeleccionado
}
}
The results so far are error while unwrapping an optional value and the text on label is not shown.

Change your method like this and check ... hopefully it will work
#IBAction func guardarTipo(_ sender: Any) {
dismiss(animated: true, completion: {
NotificationCenter.default.post(name: .guardarTipo, object: nil)
})
}

Related

Cannot subscript a value of type '[Double]' with an argument of type 'Double'

I would like to pass an array of a selected number as a Double However i get this error Cannot subscript a value of type '[Double]' with an argument of type 'Double'
Coud someone tell me what I am doing wrong? Thanks in Advance!
import UIKit
class SelectAttributesViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
#IBOutlet weak var kitPickerView: UIPickerView!
#IBOutlet weak var reactionVolumeLabel: UILabel!
#IBOutlet weak var numberOfSampleTextField: UITextField!
#IBOutlet weak var volumeOfTemplateDNATextField: UITextField!
#IBOutlet weak var slider: UISlider!
#IBOutlet weak var calculateButton: UIButton!
let kits = ["kit 1"]
let pArray: [Double] = [10,20,50]
var currentValue = Int()
override func viewDidLoad() {
super.viewDidLoad()
self.numberOfSampleTextField.delegate = self
self.volumeOfTemplateDNATextField.delegate = self
kitPickerView.dataSource = self
kitPickerView.delegate = self
//slider.addTarget(self, action: "reactionVolumeSlider", for: .valueChanged)
let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))
view.addGestureRecognizer(tap)
// Do any additional setup after loading the view.
}
func pcrSliderInterval() {
slider.minimumValue = 0
slider.maximumValue = Float(pArray.count)
slider.isContinuous = false
}
#IBAction func reactionVolumeSlider(_ sender: UISlider) {
currentValue = pArray[Double(sender.value)] // This is where I get the error
reactionVolumeLabel.text = "\(currentValue) μL"
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return kits.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row == 0{ print(kits[row])
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return kits[row]
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let oldText = textField.text, let r = Range(range, in: oldText) else {
return true
}
let newText = oldText.replacingCharacters(in: r, with: string)
let isNumeric = newText.isEmpty || (Double(newText) != nil)
let numberOfDots = newText.components(separatedBy: ".").count - 1
let numberOfDecimalDigits: Int
if let dotIndex = newText.firstIndex(of: ".") {
numberOfDecimalDigits = newText.distance(from: dotIndex, to: newText.endIndex) - 1
} else {
numberOfDecimalDigits = 0
}
return isNumeric && numberOfDots <= 1 && numberOfDecimalDigits <= 2
}
func createAlert (title: String, message: String){
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: { (Action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let masterMix = segue.destination as! MasterMixTableViewController
masterMix.numberOfSamples = numberOfSampleTextField.text!
masterMix.volumeOfTemplateDna = volumeOfTemplateDNATextField.text!
masterMix.reactionVolumeInt = currentValue
//masterMix.waterVolumeText = getWaterVolumeLabelText()
// let masterMix = segue.destination as! MasterMixTableViewController
// masterMix.loadViewIfNeeded()
// masterMix.numberOfSamples = String(numberOfSampleTextField.text)
// masterMix.waterVolumeLabel!.text = String(Double(numberOfSampleTextField.text!)! * 50
// masterMix.bufferVolumeLabel.text = String(Double(numberOfSampleTextField.text!)! * 10)
// masterMix.dNTPsVolumeLabel.text = numberOfSampleTextField!.text // done
// masterMix.forwardPrimerLabel.text = String(Double(numberOfSampleTextField.text!)! * 2.5) //done
// masterMix.reversePrimerLabel.text = String(Double(numberOfSampleTextField.text!)! * 2.5) //done
// masterMix.dnaPolymeraseLabel.text = String(Double(numberOfSampleTextField.text!)! * 0.5) //done
//answer.text = String(Int(entry.text)! * 2)
}
#IBAction func calculatePressed(_ sender: Any) {
if numberOfSampleTextField.text != ""{
performSegue(withIdentifier: "masterMixSegue", sender: self)
}
}
}
The error says that an array cannot be subscripted by a Double.
The index type of Array is Int
pArray[Int(sender.value)]
And be aware that your maximum value will cause an out-of-range crash.
You cannot say
pArray[Double(sender.value)]
You need an Int. You would need
pArray[Int(sender.value)]
Except that that is unlikely to get you the desired index and you will probably crash at runtime. You will need to calculate the right index. I have no idea what you think is the relationship between your continuous slider values and the discrete indexes of an array, so I can’t say more. Maybe a slider was the wrong choice of interface?

Set Title of UIButton from Selected Row of UIPickerView in swift

I am trying to set my Button title from a selected row from uipickerview. However, I can't seem to find a valid solution.
I have set the variables to be global thus I can access the Selected Variable. However I cant seem to be able to pinpoint exactly when the user clicks the exit button and able to update my button title.
Things I have tried:
Global Functions ( couldn't work because you cant specify the button you want to change the name of )
Dispatchqueue.main.async - Did not update my title. The idea here is for it to constantly check for a string change.
The solution I found here is in Obj-C. I tried converting it to swift https://objectivec2swift.com/#/converter/code/ with no luck.
Set Title of UIButton from Selected Row of UIPickerView
#IBAction func CountryPickButton(_ sender: UIButton) {
Global.setPickerDataSource(data:["Test","test2","test3"])
Global.setPickerCompletionHandler(int:0)
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PickerViewPopUpId") as! PickerViewController
//CountryPickButtonDetector = sender as? UIButton
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
popOverVC.callback { value in
//CountryPickButton.title.text = value
sender.setTitle(value, for: UIControl.State)
}
}
import UIKit
var test = ""
class PickerViewController: UIViewController {
#IBOutlet weak var PickerView: UIPickerView!
var callback : ((String) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
//self.view.backgroundColor = UIColor.black.withAlphaComponent(0.8)
PickerView.dataSource = self
PickerView.delegate = self
// Do any additional setup after loading the view.
}
#IBAction func ExitButton(_ sender: Any) {
switch Global.pickerCompletionHandler {
case 0:
callback?(Global.pickerResult ?? "")
Global.setProfileCountry(string:
Global.pickerResult ?? "")
default:
print("nothing")
}
self.view.removeFromSuperview()
}
}
extension PickerViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1 // can be more than 1 component like time/date/year
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return Global.pickerDataSource?.count ?? 1
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
//Global.pickerResult = Global.pickerDataSource?[row]
Global.setPickerResult(result: Global.pickerDataSource?[row] ?? "Test" )
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return Global.pickerDataSource?[row]
}
}
Globals
import Foundation
struct Global {
static var pickerDataSource:[String]? = nil
static var pickerResult:String? = nil
static var pickerCompletionHandler:Int? = 0
static var profileCountry:String? = nil
static func setPickerDataSource(data:[String]) {
Global.pickerDataSource = data
}
static func setPickerResult(result:String) {
Global.pickerResult = result
}
static func setPickerCompletionHandler(int: Int) {
Global.pickerCompletionHandler = int
}
static func setProfileCountry(string: String)
{
Global.profileCountry = string
}
}
I don't know what all that Global stuff is, the easiest solution might be to extend pickerCompletionHandler, but here is another (easy) one:
In PickerViewController add a callback passing a String value and no return value
var callback : ((String) -> Void)?
and call it in exitButton (please, please variable and function names are supposed to start with a lowercase letter)
#IBAction func exitButton(_ sender: Any) {
switch Global.pickerCompletionHandler {
case 0:
callback?(Global.pickerResult ?? "")
Global.setProfileCountry(string:
Global.pickerResult ?? "")
default:
print("nothing")
}
self.view.removeFromSuperview()
}
In countryPickButton (again: lowercase letter) set the callback and set sender to the real type. The callback sets the title
#IBAction func countryPickButton(_ sender: UIButton) {
Global.setPickerDataSource(data:["Test","test2","test3"])
Global.setPickerCompletionHandler(int:0)
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PickerViewPopUpId") as! PickerViewController
popOverVC.callback = { value in
sender.setTitle(value, for: .normal)
}
...

Can't get app to display cryptocurrency amount

From "var myValue:[Double]..." and "var activeCurrency:Double = 0;" to the third pickerview code, I am not sure what to do in order to fix the "self.myValues.append((Url as? Double)!)" so that my app displays the currency amount. I have searched everywhere, and have no luck in finding anything. You are my last hope, please help. I'm still fairly new to coding, so I may not know the certain jargon.
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var myCurrency:[String] = []
var myValues:[Double] = []
var activeCurrency:Double = 0;
//OBJECTS
#IBOutlet weak var textbox: UITextField!
#IBOutlet weak var pickerView: UIPickerView!
#IBOutlet weak var output: UILabel!
//CREATING PICKER VIEW
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return myCurrency.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myCurrency[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
activeCurrency = myValues[row]
}
//BUTTON
#IBAction func action(_ sender: AnyObject) {
if (textbox.text != "") {
output.text = String(Double(textbox.text!)! * activeCurrency)
}
}
override func viewDidLoad() {
super.viewDidLoad()
//DATA GRABBING
let url = URL(string: "https://min-api.cryptocompare.com/data/all/coinlist")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print ("ERROR")
}
else {
if let content = data {
do {
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
if let rates = myJson["Data"] as? NSDictionary {
for (Name, Url) in rates {
self.myCurrency.append((Name as? String)!)
self.myValues.append((Url as? Double)!)
}
}
}
catch {
}
}
}
if data != nil {
DispatchQueue.main.async { // Correct
self.pickerView.reloadAllComponents()
}
}
}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

how to get the value (or index) from a picker and compare it to the value of an attribute of an entity?

I have a problem in returning the value from a picker and comparing it to the value of an attribute. Basically, i have a Floor entity which has a attribute "floorNumber". From the picker I need to get the floor number and match it to the correct entity object so I can start assigning rooms to individual floors. I have implemented the delegate and the data source for the picker and looked at other questions on this site but I'm getting a bit confused.
Please have look at my implementation and please tell me what am I doing wrong. I have an optional "pickedFloor" which is nil even though it is being set and if I try to unwrap it it will crash it. Thank you for your help
class SetNumberOfRoomsPerFloor: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
//MARK: - Properties
#IBOutlet private weak var floorPicker: UIPickerView!
#IBOutlet private weak var numberOfRoomsPerFloor: UITextField!
private var managedObjectContext: NSManagedObjectContext!
internal var floorValue: Int16?
private var convertedFloorValues = [String]()
private var storedFloors = [Floors]()
private var pickedFloor: Int16?
private var roomNumberValue: Int16 {
get {
return Int16(numberOfRoomsPerFloor.text!)!
}
}
override func viewDidLoad() {
super.viewDidLoad()
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
floorPicker.delegate = self
floorPicker.dataSource = self
loadFloorData()
spinnerItems()
}
#IBAction func setTheFloors(_ sender: UIButton) {
if storedFloors.count > 0 {
if storedFloors.first?.floorNumber == pickedFloor {
storedFloors.first?.numberOfRooms = roomNumberValue
print("\(storedFloors.first?.floorNumber) + \(storedFloors.first?.numberOfRooms)")
}
}
}
#IBAction func nextStep(_ sender: UIButton) {}
private func loadFloorData() {
let floorRequest: NSFetchRequest<Floors> = Floors.fetchRequest()
do {
storedFloors = try managedObjectContext.fetch(floorRequest)
} catch {
print("could not load data from core \(error.localizedDescription)")
}
}
private func spinnerItems() {
for i in 0...floorValue! - 1 {
convertedFloorValues.append(String(i))
}
}
public func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return convertedFloorValues.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return convertedFloorValues[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let selection = Int16(convertedFloorValues[row]) // not sure I have to do this part.
pickedFloor = selection
}
}
Inside this function, you should do this
private func spinnerItems() {
for i in 0...floorValue! - 1 {
convertedFloorValues.append(String(i))
}
if convertedFloorValues.count >= 1 {
pickedFloor = Int16(convertedFloorValues[0])
}
}
Like I said in the comments, didSelectRow never gets called if you don't actually move the picker view.
If the user hasn't selected anything in pickerview then pickedFloor will be nil.Try this.
#IBAction func setTheFloors(_ sender: UIButton) {
if storedFloors.count > 0 {
if storedFloors.first?.floorNumber == convertedFloorValues[floorPicker.selectedRow(inComponent: 0)] {
storedFloors.first?.numberOfRooms = roomNumberValue
print("\(storedFloors.first?.floorNumber) + \(storedFloors.first?.numberOfRooms)")
}
}
}

found nil while unwrapping an ViewController Optional

I am building a very simple swift application that uses two view controllers - "ViewControler" and "AnimalChooserViewControler". First has a simple label and a toolbar with one item, which transfers the user to the second screen. In the second, have custom picker. The whole purpose of the app is to display whatever the user has selected from the second view controler to the first one using the output UILabel. I have to mention that I am usong xCode 6.4 (ios8)
My problem is when I try to cast the presentedViewController as! ViewController the app crashes with "fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)" exceptions. How to solve this problem, any suggestions?
Here is my code in the ViewControler:
class ViewController: UIViewController {
#IBOutlet weak var outputLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func displayAnimal(choosenAnimal: String, withSound choosenSound: String, fromComponent choosenComponent: String){
self.outputLabel.text = "You changed \(choosenComponent) (\(choosenAnimal)(and the sound \(choosenSound))"
}
}
And this is my code in AnimalChooserViewControler
class AnimalChooserViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate{
let kComponentCount: Int = 2
let kAnimalComponent: Int = 0
let kSoundComponent: Int = 1
var animalNames: [String] = []
var animalSounds: [String] = []
var animalImages: [UIImageView] = []
#IBAction func dismisAnimalChooser(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return kComponentCount
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == kAnimalComponent{
return animalNames.count
} else {
return animalSounds.count
}
}
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {
if component == kAnimalComponent {
let choosenImageView: UIImageView = animalImages[row]
let workarroundImageView: UIImageView = UIImageView(frame: choosenImageView.frame)
workarroundImageView.backgroundColor = UIColor(patternImage: choosenImageView.image!)
return workarroundImageView
} else {
let soundLabel: UILabel = UILabel(frame: CGRectMake(0, 0, 100, 32))
soundLabel.text = animalSounds[row]
return soundLabel
}
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 55.0
}
func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
if component == kAnimalComponent{
return 75.0
} else {
return 150.0
}
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let initialView : ViewController = presentedViewController as! ViewController
if component == kAnimalComponent{
let choosenSound: Int = pickerView.selectedRowInComponent(self.kSoundComponent)
initialView.displayAnimal(animalNames[row], withSound: animalSounds[choosenSound], fromComponent: "the Animal")
} else {
let choosenAnimal: Int = pickerView.selectedRowInComponent(kAnimalComponent)
initialView.displayAnimal(animalNames[choosenAnimal], withSound: animalSounds[row], fromComponent: "the Sound")
}
}
override func viewDidLoad() {
super.viewDidLoad()
animalNames = ["Mouse","Goose","Cat","Dog","Snake","Bear","Pig"]
animalSounds = ["Oink","Rawr","Sss","Meow","Honk","Squeak"]
animalImages = [UIImageView(image: UIImage(named: "mouse.png")),
UIImageView(image: UIImage(named: "goose.png")),
UIImageView(image: UIImage(named: "cat.png")),
UIImageView(image: UIImage(named: "dog.png")),
UIImageView(image: UIImage(named: "snake.png")),
UIImageView(image: UIImage(named: "bear.png")),
UIImageView(image: UIImage(named: "pig.png"))]
preferredContentSize = CGSizeMake(340,380)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let initialView: ViewController = presentedViewController as! ViewController
initialView.displayAnimal(animalNames[0], withSound: animalSounds[0], fromComponent: "nothing yet...")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// 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.
}
*/
}
I found what was causing the exception. I have used "presentedViewController" instead of "presentingViewController". Silly mistake but it took me a good hour to find it out :)