Non- adjacent view controllers

Here is my situation. I have some common processing code (function) in VC1 - this is common code that other view controllers will call. Basically, a user enters a value into say VC3 - VC1 will process the value. Since I have multiple VC's who do the same actions for a different activity (e.g, enter weight lifted for legs vs fly) I want to minimize th common code. It all works great as long as the VC2 and VC3 are directly wired to the VC1.


I currently use the suegue approach but am stuck on this one.


I suspect it is how I have the VC's wired and is simple to correct 🙂


Help please! Can post eisting code if that would assist.

Replies

A couple of questions and comments:


1 - What do you mean about VC2 and VC3 being directly wired to VC1? Did VC2 and VC3 have a reference to VC1 in their state (which you could setup by using an IBOutlet and connecting them????)? Did you have notifications setup between VC1 and VC2/VC3? When they were wired, how did you get to the common code?


2 - Is VC1 maintaining state or have references to other objects that VC2 and VC3 can't access except for going through VC1? Does the common code have state variables or properties that it manipulates that are part of VC1?


3 - Have you considered isolating the common code into a function that can be called from all 3 view controllers, thus, not requiring that there be any connection between the 3?


4 - Where is your model being kept? From your description, it seems like this code is model related, and should be part of your model code, not the controller code. But, if it is code that, for example, translates units, that needs to be used by all the controllers, it probably needs to be factored out into a separate function.

#3 is exactly what I want to do. My only requirement is to pass back data (core storage) to display data - I want the write-to-core, read-from-core to be in a common accessible space. I thought using delegate and segue was the way to do that. I can post or send code if that is helpful.


Here is my VC1 with some common functions

import UIKit
import CoreData
var valuetest = ""

class TimeSensitiveChestWorkout1: UIViewController, WeightProtocol {
    var Pressed: String!

    
    @IBOutlet weak var logo: UIImageView!
    @IBOutlet weak var Workout1: UIButton!
    @IBOutlet weak var Workout2: UIButton!
    @IBOutlet weak var Workout3: UIButton!

    @IBAction func didPressButton(sender:  AnyObject) {
        Pressed = "DumbbellPress"
        print ("*******  Dumbbell button pressed: ", Pressed!)
    }
    
    @IBAction func inclineDumbbellPress(_ sender: Any) {
        Pressed = "inclineViewController"
        print (Pressed)
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        logo.layer.cornerRadius = 25
        logo.layer.masksToBounds = true
        logo.layer.borderColor = UIColor.white.cgColor
        logo.layer.borderWidth = 3
        
        Workout1.layer.cornerRadius = 20
        Workout1.layer.masksToBounds = true
        Workout1.layer.borderColor = UIColor.white.cgColor
        Workout1.layer.borderWidth = 2
        
        Workout2.layer.cornerRadius = 20
        Workout2.layer.masksToBounds = true
        Workout2.layer.borderColor = UIColor.white.cgColor
        Workout2.layer.borderWidth = 2
        
        Workout3.layer.cornerRadius = 20
        Workout3.layer.masksToBounds = true
        Workout3.layer.borderColor = UIColor.white.cgColor
        Workout3.layer.borderWidth = 2
    }
    
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (Pressed == "DumbbellPress") {
            let destination = segue.destination as! DumbbellChestPress
            destination.delegate = self
        }
        else if (Pressed == "inclineViewController") {
            let destination = segue.destination as! inclineViewController
            destination.delegate = self
        }
        else {
            print ("******** No button press")
        }
    }
    
    
    func updateDataGlobal(EntityVar: String, ExeriseNameVar: String, value:String){
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        
        let fetchRequest:NSFetchRequest = NSFetchRequest.init(entityName: EntityVar)
    fetchRequest.predicate = NSPredicate(format: "name = %@", ExeriseNameVar)
        do
        {
            let test = try managedContext.fetch(fetchRequest)
            let objectUpdate = test[0] as! NSManagedObject
            objectUpdate.setValue(value, forKey: "weight")
            do{
                try managedContext.save()
                print ("Record Updated: ",value, " for: ", ExeriseNameVar)
            }
            catch
            {
                print("Error: ",error)
            }
        }
        catch
        {
            print(error)
        }
    }
    
    
    func retrieveDataGlobal(EntityVar: String, ExeriseNameVar: String, value:String) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        
        let fetchRequest = NSFetchRequest(entityName: "Chest")
        
        fetchRequest.fetchLimit = 5
        fetchRequest.predicate = NSPredicate(format: "name = %@", ExeriseNameVar)
        
        let count = try! managedContext.count(for: fetchRequest)
        print ("retrieveDataGlobal record count: ", count)
 //       if (count == 0){
 //           createData()
 //       }
        print (count)

        do {
            let result = try managedContext.fetch(fetchRequest)
            
            for data in result as! [NSManagedObject] {
                print("********** Data Retrieved - weight:  ", data.value(forKey: "weight") as! String)
                valuetest = data.value(forKey: "weight") as! String
                print ("+++++++++++++  valuetest: ", valuetest)
            }
        } catch {
            print("Failed")
        }
    }
    

}



Here is my VC2 which is connected direct in the storyboard but if there is another VC in the IOutlet path it doesnt work

import UIKit
import CoreData

protocol WeightProtocol {
    func updateDataGlobal(EntityVar: String, ExeriseNameVar: String, value:String)
    func retrieveDataGlobal(EntityVar: String, ExeriseNameVar: String, value:String)
}

extension UIViewController {
    func HideKeyboard() {
        let Tap:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(DismissKeyboard))
        view.addGestureRecognizer(Tap)
    }
    @objc func DismissKeyboard() {
        view.endEditing(true)
    }
}

class DumbbellChestPress: UIViewController {
    var delegate: WeightProtocol!

    @IBOutlet weak var newMaxLiftText: UITextField!
    @IBOutlet weak var newMaxLiftLabel: UILabel!
    @IBOutlet weak var maxWeightLiftedLabel: UILabel!
    
    @IBAction func newWeightButon(_ sender: UIButton) {
        maxWeightLiftedLabel.text = newMaxLiftText.text
        delegate?.updateDataGlobal(EntityVar: "Chest", ExeriseNameVar: "Dumbell Chest Press", value: maxWeightLiftedLabel.text!)
        self.dismiss(animated: true, completion: nil)
//        updateData()
    }
    
    @IBAction func delerteDataBtton(_ sender: UIButton) {
        deleteData()
    }
    
    @IBAction func loadDataButton(_ sender: UIButton) {
        createData()
    }
    
    @IBOutlet weak var Workout1: UIImageView!
    @IBOutlet weak var Workout2: UIImageView!
    
    @IBOutlet weak var Workout4: UIImageView!
    @IBOutlet weak var Workout3: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.HideKeyboard()
        
        delegate?.retrieveDataGlobal(EntityVar: "Chest", ExeriseNameVar: "Dumbell Chest Press", value: maxWeightLiftedLabel.text!)

       maxWeightLiftedLabel.text = valuetest
        
        Workout1.layer.cornerRadius = 20
        Workout1.layer.masksToBounds = true
        Workout1.layer.borderColor = UIColor.white.cgColor
        Workout1.layer.borderWidth = 2
        
        Workout2.layer.cornerRadius = 20
        Workout2.layer.masksToBounds = true
        Workout2.layer.borderColor = UIColor.white.cgColor
        Workout2.layer.borderWidth = 2
        
        Workout3.layer.cornerRadius = 20
        Workout3.layer.masksToBounds = true
        Workout3.layer.borderColor = UIColor.white.cgColor
        Workout3.layer.borderWidth = 2
        
        Workout4.layer.cornerRadius = 20
        Workout4.layer.masksToBounds = true
        Workout4.layer.borderColor = UIColor.white.cgColor
        Workout4.layer.borderWidth = 2

        // Do any additional setup after loading the view.
    }
   
}