簡體   English   中英

跨 Swift 中的多個選項卡訪問相同的視圖 Model

[英]Access same View Model across multiple tabs in Swift

背景

我有一個鍛煉VM 視圖workoutVM可以容納我的大部分視圖模型,我想將其傳遞給我的應用程序中的所有其他視圖控制器。 我的應用程序還有一個標簽欄 controller,我用它來存儲一些數據,例如用戶信息等。

問題 1

在此處輸入圖像描述

即使我在MyTrainingViewController (“主頁”選項卡)中創建了workoutVM視圖 model(帶有值),我也無法通過使用將視圖 model(帶有值)傳遞到下一個ExerciseSetsViewController集視圖控制器(“鍛煉”選項卡)

  1. 方法 1 - 通過使用委托MyTrainingViewControllerDelegate和/或
  2. 方法 2 - 通過實例化ExerciseSetsViewController並加載視圖。

當用戶選擇特定的表格視圖單元格時,將運行通過鍛煉VM 視圖workoutVM的代碼/操作。

我真的不確定為什么其中任何一種方法都有效,因為類似的方法適用於許多其他場景。 下面是 Xcode 調試器,顯示我使用這兩種方法的代碼沒有將鍛煉虛擬機視圖 model 傳遞給ExerciseSetsViewController

在此處輸入圖像描述

問題 2

結果,我找到了一種解決方法(方法 3 在下面的代碼中被注釋掉了)來利用 tabbar 來存儲鍛煉虛擬機視圖workoutVM (再次依靠 tabbar 在多個視圖控制器之間傳遞和共享數據)。

在這一點上,我擔心我的應用實際上是在使用 tabbar 作為“單例”,盡管我“有點”理解它不是完全“單例”。

我認為,理想情況下,視圖模型應該充當某種數據模型,它們可以在多個視圖控制器之間共享/操作/傳遞,而無需將標簽欄作為中間層。 那不是正確的嗎? 或者這是我通過使用標簽欄采用的最佳/良好做法?

protocol MyTrainingViewControllerDelegate {
    func passWorkoutVM(workoutVM: WorkoutViewModel)
}

class MyTrainingViewController: UIViewController {

    var workoutVM: WorkoutViewModel?
    
    var delegate: MyTrainingViewControllerDelegate!

    @IBOutlet weak var dayProgramTableView: UITableView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
     
        dayProgramTableView.delegate = self
        dayProgramTableView.dataSource = self
      }
}

extension MyTrainingViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     
        let tabbar = tabBarController as! MainTabBarController

        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let ExerciseSetsViewController = storyBoard.instantiateViewController(withIdentifier: "ExerciseSetsView") as! ExerciseSetsViewController

        guard let workoutVM = self.workoutVM else {
            return
        }
        
        print("printing workoutViewModel dayprogram no.of exercise at HomeView \(workoutVM.dayprograms[indexPath.row].dayprogram.dayIntensity)")
        
        //1.Instantiate view via storyboard Method
        ExerciseSetsViewController.loadViewIfNeeded()
        ExerciseSetsViewController.workoutVM = workoutVM
        
        //2.Delegate Method
        self.delegate?.passWorkoutVM(workoutVM: workoutVM)
        
        //3.Tabbar Method
//        tabbar.workoutVM = workoutVM

        tabbar.selectedIndex = 1
    }
}
class ExerciseSetsViewController: UIViewController {
      var workoutVM: WorkoutViewModel?
      
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)

        // ** To do
        //create workoutViewModel
         //3.Tabbar Method
//        self.workoutVM = tabbar.workoutVM

        print("printing workoutViewModel to check if workoutVM had been passed from MyTrainingView \(String(describing: self.workoutVM))")

  }
  
}

extension ExerciseSetsViewController: MyTrainingViewControllerDelegate {
    
    func passWorkoutVM(workoutVM: WorkoutViewModel) {
        self.workoutVM = workoutVM
        print("passWorkoutDelegate Method executed")
    }
    
}
class MainTabBarController: UITabBarController {

    var workoutVM: WorkoutViewModel?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

在一些外部幫助下,我能夠確定第一個問題的根源並加以糾正。 我還能夠聽到關於第二個問題的必要建議。

問題 1

問題是我“通過故事板實例化”的exerciseSetsViewControllerTabbarController的第二個選項卡(鍛煉選項卡)中顯示的exerciseSetsViewController不同。 因此, workoutVM沒有傳遞給正確的視圖控制器。 因此,如果我想使用以下任何一個,則需要使用以下更正的代碼

  1. 方法 1 - 通過使用委托MyTrainingViewControllerDelegate和/或
  2. 方法 2 - 通過實例化ExerciseSetsViewController並加載視圖。

更正后的代碼確保實例化的exerciseSetsViewController被放置為TabbarController的第二個選項卡。

protocol MyTrainingViewControllerDelegate {
    func passWorkoutVM(workoutVM: WorkoutViewModel)
}

class MyTrainingViewController: UIViewController {

    var workoutVM: WorkoutViewModel?
    
    var delegate: MyTrainingViewControllerDelegate!

    @IBOutlet weak var dayProgramTableView: UITableView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
     
        dayProgramTableView.delegate = self
        dayProgramTableView.dataSource = self
      }
}

extension MyTrainingViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     
        let tabbar = tabBarController as! MainTabBarController

        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let ExerciseSetsViewController = storyBoard.instantiateViewController(withIdentifier: "ExerciseSetsView") as! ExerciseSetsViewController

        guard let workoutVM = self.workoutVM else {
            return
        }
                let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let exerciseSetsViewController = storyBoard.instantiateViewController(withIdentifier: "ExerciseSetsView") as! ExerciseSetsViewController

        guard let nav = tabbar.viewControllers?[1] as? UINavigationController, let exerciseSetsViewController = nav.viewControllers.first as? ExerciseSetsViewController else { return }
        
        print("printing workoutViewModel dayprogram no.of exercise at MyTrainingView \(workoutVM.dayprograms[indexPath.row].dayprogram.dayIntensity)")
        
//        1.Instantiate view via storyboard Method
        exerciseSetsViewController.loadViewIfNeeded()
        exerciseSetsViewController.workoutVM = workoutVM

//        2.Delegate Method
        self.delegate?.passWorkoutVM(workoutVM: workoutVM)
}

問題 2

我被告知我使用“標簽欄”的方法與使用“單例”的方法實際上是相同的,因為有一個共享的數據源可以訪問多個視圖。 同樣,我利用可通過多視圖 controller 訪問的視圖模型的方法與使用“全局”變量相同,這與使用“單例”具有相似的影響。

雖然這種方法在某些情況下是可以接受的,但這不是“最佳實踐” ,我需要更改我的一些代碼/方法,其中每個視圖 controller 都有自己的一組數據/視圖模型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM