How can I save several UISwitches and thus display different arrays of a Pickerview?

42 Views Asked by At

I am in the process of programming a small app to calculate exposure times.

I have a UiViewController to set the apertures of one Stop, halfStop and thridStop via three UiSwitches.

If you set one UiSwitch to .isON == true, the other two switch to .isOn == false. This also works perfectly.

I also have a button that can be used to return to the previous ViewController. UiSwitch states should be saved with a tap on this button.

If one of the switches is selected, the corresponding array should be displayed in the PickerView.

This works perfectly with a single array, but I can't manage with several.

And that's the problem, I've read a lot here and tried a lot, but it just doesn't work.

Here is the codes as I have written it so far:

ApertureModel:

class ApertureModel {
    
    var aperture: String
    var f: Double
    
    init(_aperture: String, _f: Double) {
        self.aperture = _aperture
        self.f = _f
    }
}

Aperture Data

import Foundation
class ApertureData {

    class func DataOneStop() -> [ApertureModel] {
        var dataAperture = [ApertureModel]()

        dataAperture.append(ApertureModel(_aperture: "f:0.5", _f: 0.5))
        dataAperture.append(ApertureModel(_aperture: "f:0.7", _f: 0.7))
        dataAperture.append(ApertureModel(_aperture: "f:1.0", _f: 1.0))
        dataAperture.append(ApertureModel(_aperture: "f:1.1", _f: 1.1))
        dataAperture.append(ApertureModel(_aperture: "f:1.2", _f: 1.2))
        dataAperture.append(ApertureModel(_aperture: "f:1.4", _f: 1.4))
        dataAperture.append(ApertureModel(_aperture: "f:1.6", _f: 1.6))
        dataAperture.append(ApertureModel(_aperture: "f:1.8", _f: 1.8))
        dataAperture.append(ApertureModel(_aperture: "f:2.0", _f: 2.0))
        dataAperture.append(ApertureModel(_aperture: "f:2.2", _f: 2.2))
        dataAperture.append(ApertureModel(_aperture: "f:2.5", _f: 2.5))
        dataAperture.append(ApertureModel(_aperture: "f:2.8", _f: 2.8))
        dataAperture.append(ApertureModel(_aperture: "f:3.2", _f: 3.2))
        dataAperture.append(ApertureModel(_aperture: "f:4.0", _f: 4.0))
        dataAperture.append(ApertureModel(_aperture: "f:4.5", _f: 4.5))
        dataAperture.append(ApertureModel(_aperture: "f:5.0", _f: 5.0))
        dataAperture.append(ApertureModel(_aperture: "f:5.6", _f: 5.6))
        dataAperture.append(ApertureModel(_aperture: "f:6.3", _f: 6.3))
        dataAperture.append(ApertureModel(_aperture: "f:7.2", _f: 7.2))
        dataAperture.append(ApertureModel(_aperture: "f:8.0", _f: 8.0))
        dataAperture.append(ApertureModel(_aperture: "f:9.0", _f: 9.0))
        dataAperture.append(ApertureModel(_aperture: "f:10", _f: 10.0))
        dataAperture.append(ApertureModel(_aperture: "f:11", _f: 11.0))
        dataAperture.append(ApertureModel(_aperture: "f:13", _f: 13.0))
        dataAperture.append(ApertureModel(_aperture: "f:14", _f: 14.0))
        dataAperture.append(ApertureModel(_aperture: "f:16", _f: 16.0))
        dataAperture.append(ApertureModel(_aperture: "f:18", _f: 18.0))
        dataAperture.append(ApertureModel(_aperture: "f:20", _f: 20.0))
        dataAperture.append(ApertureModel(_aperture: "f:22", _f: 22.0))
        dataAperture.append(ApertureModel(_aperture: "f:25", _f: 22.0))
        dataAperture.append(ApertureModel(_aperture: "f:29", _f: 29.0))
        dataAperture.append(ApertureModel(_aperture: "f:32", _f: 32.0))
        dataAperture.append(ApertureModel(_aperture: "f:36", _f: 36.0))
        dataAperture.append(ApertureModel(_aperture: "f:40", _f: 40.0))
        dataAperture.append(ApertureModel(_aperture: "f:45", _f: 45.0))
        dataAperture.append(ApertureModel(_aperture: "f:64", _f: 64.0))
        dataAperture.append(ApertureModel(_aperture: "f:90", _f: 90.0))
        dataAperture.append(ApertureModel(_aperture: "f:128", _f: 128.0))
        dataAperture.append(ApertureModel(_aperture: "f:256", _f: 256.0))
        dataAperture.append(ApertureModel(_aperture: "f:512", _f: 512.0))
        dataAperture.append(ApertureModel(_aperture: "f:1024", _f: 1024.0))

        return dataAperture
    }
    
    class func DataHalfStop() -> [ApertureModel] {
        var dataAperture = [ApertureModel]()
        
        dataAperture.append(ApertureModel(_aperture: "f/1.0", _f: 1.0))
        dataAperture.append(ApertureModel(_aperture: "f/1.2", _f: 1.2))
        dataAperture.append(ApertureModel(_aperture: "f/1.4", _f: 1.4))
        dataAperture.append(ApertureModel(_aperture: "f/1.7", _f: 1.7))
        dataAperture.append(ApertureModel(_aperture: "f/2.0", _f: 2.0))
        dataAperture.append(ApertureModel(_aperture: "f/2.4", _f: 2.4))
        dataAperture.append(ApertureModel(_aperture: "f/2.8", _f: 2.8))
        dataAperture.append(ApertureModel(_aperture: "f/3.3", _f: 3.3))
        dataAperture.append(ApertureModel(_aperture: "f/4.0", _f: 4.0))
        dataAperture.append(ApertureModel(_aperture: "f/4.8", _f: 4.8))
        dataAperture.append(ApertureModel(_aperture: "f/5.6", _f: 5.6))
        dataAperture.append(ApertureModel(_aperture: "f/6.7", _f: 6.7))
        dataAperture.append(ApertureModel(_aperture: "f/8.0", _f: 8.0))
        dataAperture.append(ApertureModel(_aperture: "f/9.5", _f: 9.5))
        dataAperture.append(ApertureModel(_aperture: "f/10", _f: 10.0))
        dataAperture.append(ApertureModel(_aperture: "f/11", _f: 11.0))
        dataAperture.append(ApertureModel(_aperture: "f/14", _f: 14.0))
        dataAperture.append(ApertureModel(_aperture: "f/16", _f: 16.0))
        dataAperture.append(ApertureModel(_aperture: "f/19", _f: 19.0))
        dataAperture.append(ApertureModel(_aperture: "f/22", _f: 22.0))
        dataAperture.append(ApertureModel(_aperture: "f/27", _f: 27.0))
        dataAperture.append(ApertureModel(_aperture: "f/32", _f: 32.0))
        dataAperture.append(ApertureModel(_aperture: "f/38", _f: 38.0))
        dataAperture.append(ApertureModel(_aperture: "f/45", _f: 45.0))
        dataAperture.append(ApertureModel(_aperture: "f/54", _f: 54.0))
        dataAperture.append(ApertureModel(_aperture: "f/64", _f: 64.0))
        dataAperture.append(ApertureModel(_aperture: "f/76", _f: 76.0))
        dataAperture.append(ApertureModel(_aperture: "f/107", _f: 107.0))
        dataAperture.append(ApertureModel(_aperture: "f/128", _f: 128.0))
        dataAperture.append(ApertureModel(_aperture: "f/215", _f: 215.0))
        dataAperture.append(ApertureModel(_aperture: "f/256", _f: 253.0))
        dataAperture.append(ApertureModel(_aperture: "f/430", _f: 430.0))
        dataAperture.append(ApertureModel(_aperture: "f/512", _f: 512.0))
        dataAperture.append(ApertureModel(_aperture: "f/860", _f: 860.0))
        dataAperture.append(ApertureModel(_aperture: "f/1024", _f: 1024.0))
        
        return dataAperture
    }
    
    
    class func DataThirdStop() -> [ApertureModel] {
        var dataAperture = [ApertureModel]()
        
        dataAperture.append(ApertureModel(_aperture: "f/1.0", _f: 1.0))
        dataAperture.append(ApertureModel(_aperture: "f/1.4", _f: 1.4))
        dataAperture.append(ApertureModel(_aperture: "f/2.0", _f: 2.0))
        dataAperture.append(ApertureModel(_aperture: "f/2.8", _f: 2.8))
        dataAperture.append(ApertureModel(_aperture: "f/4.0", _f: 4.0))
        dataAperture.append(ApertureModel(_aperture: "f/5.6", _f: 5.6))
        dataAperture.append(ApertureModel(_aperture: "f/8.0", _f: 8.0))
        dataAperture.append(ApertureModel(_aperture: "f/11", _f: 11.0))
        dataAperture.append(ApertureModel(_aperture: "f/16", _f: 16.0))
        dataAperture.append(ApertureModel(_aperture: "f/22", _f: 22.0))
        dataAperture.append(ApertureModel(_aperture: "f/32", _f: 32.0))
        dataAperture.append(ApertureModel(_aperture: "f/45", _f: 45.0))
        dataAperture.append(ApertureModel(_aperture: "f/64", _f: 64.0))
        dataAperture.append(ApertureModel(_aperture: "f/90", _f: 90.0))
        dataAperture.append(ApertureModel(_aperture: "f/128", _f: 128.0))
        dataAperture.append(ApertureModel(_aperture: "f/256", _f: 256.0))
        dataAperture.append(ApertureModel(_aperture: "f/512", _f: 512.0))
        dataAperture.append(ApertureModel(_aperture: "f/1024", _f: 1024.0))
        
        return dataAperture
    }
        
        
}

PickerView

import UIKit

class SelectAperture: UIViewController {
    
    @IBOutlet weak var aperturePicker: UIPickerView!
    
    var delegateAperture: apertureDelegate? = nil
    var apertureModelThird = [ApertureModel]()
    let defaults = UserDefaults.standard
    
    
    //MARK: - Unwind 
    @IBAction func unwindAperture(_ sender: UIStoryboardSegue) {
        dismiss(animated: true, completion: nil)

    }
    

    override func viewDidLoad() {
        super.viewDidLoad()
        
        aperturePicker.dataSource = self
        aperturePicker.delegate = self
        apertureModelThird = ApertureData.DataOneStop()
        
        
        
        
        //MARK: - Notification
        
        if let selectedRow = defaults.object(forKey: "saveAperturePicker") as? Int {
            aperturePicker.selectRow(selectedRow, inComponent: 0, animated: true)
        }
        
        NotificationCenter.default.addObserver(self, selector: #selector(aperturePickerChanged), name: Notification.Name.pickersChanged, object: nil)
        
    }
    
        //MARK: - Func PickerChanced
    
    @objc func aperturePickerChanged() {
        let values = aperturePicker.selectedRow(inComponent: 0)
        _ = apertureModelThird[values...values]
    }
    
}



        //MARK: - PickerView Delegate

extension SelectAperture: UIPickerViewDelegate {
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        apertureModelThird[row].aperture
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        NotificationCenter.default.post(name: Notification.Name.pickersChanged, object: self)
        
        //MARK: - Speicherung der PickerRow
        
        let rowDefaults = defaults
        rowDefaults.set(row, forKey: "saveAperturePicker")
    }
    
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        
        let pickerText = UILabel()
        pickerText.textColor = UIColor.white
        pickerText.text = apertureModelThird[row].aperture
        pickerText.font = UIFont.boldSystemFont(ofSize: 20)
        pickerText.textAlignment = NSTextAlignment.center
        return pickerText
    }
    
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        30
    }
}



        //MARK: - PickerView DataSource

extension SelectAperture: UIPickerViewDataSource {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        apertureModelThird.count
    }
}

        //MARK: - Extension Notification

extension Notification.Name {
    static let pickersChanged = Notification.Name("PickerChanged")
}

//MARK: - Delegate
protocol apertureDelegate {
func apertureValue(aperture: String)
}

UISwitches

import UIKit

class SelectApertureStops: UIViewController {
    
    @IBOutlet weak var oneStopSwitch: UISwitch!
    @IBOutlet weak var halfStopSwitch: UISwitch!
    @IBOutlet weak var thirdStopSwitch: UISwitch!
    
    let switchDelfault = UserDefaults.standard
    
    //MARK: - Unwind
    @IBAction func unwindStops(_ sender: UIStoryboardSegue) {
        dismiss(animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        oneStopSwitch.isOn = switchDelfault.bool(forKey: "switchStateOne")
        halfStopSwitch.isOn = switchDelfault.bool(forKey: "switchStateHalf")
        thirdStopSwitch.isOn = switchDelfault.bool(forKey: "switchStateThird")
    }

    @IBAction func oneStopSwitchChanged(_ sender: UISwitch) {
        if (sender.isOn == true) {
            halfStopSwitch.isOn = false
            thirdStopSwitch.isOn = false
            
       
        } else if sender.isOn == false && halfStopSwitch.isOn == false && thirdStopSwitch.isOn == false {
            oneStopSwitch.isOn = true
        }
        switchDelfault.set(sender.isOn, forKey: "switchStateOne")
    }
    
    @IBAction func halfStopSwitchChanged(_ sender: UISwitch) {
        if sender.isOn == true {
            oneStopSwitch.isOn = false
            thirdStopSwitch.isOn = false
            
    
        } else if oneStopSwitch.isOn == false && halfStopSwitch.isOn == false && thirdStopSwitch.isOn == false {
            halfStopSwitch.isOn = true
        }
        switchDelfault.set(sender.isOn, forKey: "switchStateHalf")
    }
    
    @IBAction func thirdStopSwitchChanged(_ sender: UISwitch) {
        if sender.isOn == true {
            oneStopSwitch.isOn = false
            halfStopSwitch.isOn = false
            
      
        } else if oneStopSwitch.isOn == false && halfStopSwitch.isOn == false && thirdStopSwitch.isOn == false {
            thirdStopSwitch.isOn = true
        }
        switchDelfault.set(sender.isOn, forKey: "switchStateThird")
    }
}

I would be very happy if you could help me, because I just can't get any further.

I'm still a beginner in Swift5, I've learnt a lot in the meantime, but unfortunately I'm failing with this problem.

1

There are 1 best solutions below

0
flanker On

The solution below provides a simplified approach to the problem you outline.

It uses an enum to track the active switch, and then uses that to drive the updates to the pickers' content through the pickerView(_:titleForRow:forComponent:) delegate method and the state of the switches.

It also uses a single method to handle changes in all 3 switches. In the solution below I use code to generate the UI components so that it forms a working example. You'd need to adapt it to use your IB elements, but the same principles would apply.

[I've just thrown the UI elements into stack views to keep things simple]

class TempVC : UIViewController {
   enum ActiveSwitch {
      case s1, s2, s3
   }
   
   lazy var switch1 = UISwitch(frame: .zero, primaryAction: UIAction(title: "S1", handler: switchesChanged))
   lazy var switch2 = UISwitch(frame: .zero, primaryAction: UIAction(title: "S2", handler: switchesChanged))
   lazy var switch3 = UISwitch(frame: .zero, primaryAction: UIAction(title: "S3", handler: switchesChanged))
   
   //quick and dirty data sources for each option
   let switch1Data = ["s1L1", "s1L2", "s1L3", "s1L4", "s1L5"]   
   let switch2Data = ["s2L1", "s2L2", "s2L3", "s2L4", "s2L5"]
   let switch3Data = ["s3L1", "s3L2", "s3L3", "s3L4", "s3L5"]

   lazy var picker = UIPickerView()
   
   //just for display purposes, not functionally relevant to the question
   lazy var sStack = {
      let stack = UIStackView(arrangedSubviews: [switch1, switch2, switch3])
      stack.axis = .horizontal
      stack.alignment = .center
      stack.distribution = .equalSpacing
      stack.spacing = 20
      return stack
   }()
   
   //just for display purposes, not functionally relevant to the question
   lazy var vStack = {
      let stack = UIStackView(arrangedSubviews: [sStack, picker])
      stack.axis = .vertical
      stack.translatesAutoresizingMaskIntoConstraints = false
      return stack
   }()
   
   var activeSwitch = ActiveSwitch.s1 {
      didSet {
         setSwitches(for: activeSwitch)
         picker.reloadAllComponents()
      }
   }
   
   override func viewDidLoad() {
      super.viewDidLoad()
      view.backgroundColor = .systemBackground
      picker.delegate = self
      picker.dataSource = self
      setSwitches(for: activeSwitch)
      view.addSubview(vStack)
      NSLayoutConstraint.activate([
         vStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
         vStack.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
         vStack.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 50),
         vStack.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -50),
      ])
   }
   
   func switchesChanged(_ action: UIAction) {
      switch action.sender as! UISwitch {
         case switch1: activeSwitch = .s1
         case switch2: activeSwitch = .s2
         case switch3: activeSwitch = .s3
         default: fatalError()
      }
   }
   
   func setSwitches(for active: ActiveSwitch) {
      switch1.setOn(active == .s1, animated: true)
      switch2.setOn(active == .s2, animated: true)
      switch3.setOn(active == .s3, animated: true)
   }
}

extension TempVC: UIPickerViewDelegate {
   func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int ) -> String?  {
      return switch activeSwitch {
         case .s1: switch1Data[row]
         case .s2: switch2Data[row]
         case .s3: switch3Data[row]
      }
   }
}

extension TempVC: UIPickerViewDataSource{
   func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }   
   func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 5 }
}