[英]Access same View Model across multiple tabs in Swift
背景
我有一個鍛煉VM 視圖workoutVM
可以容納我的大部分視圖模型,我想將其傳遞給我的應用程序中的所有其他視圖控制器。 我的應用程序還有一個標簽欄 controller,我用它來存儲一些數據,例如用戶信息等。
問題 1
即使我在MyTrainingViewController
(“主頁”選項卡)中創建了workoutVM
視圖 model(帶有值),我也無法通過使用將視圖 model(帶有值)傳遞到下一個ExerciseSetsViewController
集視圖控制器(“鍛煉”選項卡)
MyTrainingViewControllerDelegate
和/或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
問題是我“通過故事板實例化”的exerciseSetsViewController
與TabbarController
的第二個選項卡(鍛煉選項卡)中顯示的exerciseSetsViewController
不同。 因此, workoutVM
沒有傳遞給正確的視圖控制器。 因此,如果我想使用以下任何一個,則需要使用以下更正的代碼
MyTrainingViewControllerDelegate
和/或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.