在Xcode Swift4中实现多ViewController共享自定义模型实例
Hey there! Since you're a Swift newbie working on a code-only project (no Storyboards, all VC setup in AppDelegate), let's figure out how to get your three child VCs sharing and reacting to changes in that custom model instance from your main VC. Here are the best approaches to try, plus some search keywords to dig deeper:
This is the cleanest, most maintainable way to share your model. The idea is simple: your main VC creates the custom model instance, then passes it directly to each child VC when initializing them.
To make the child VCs react to changes in the model, you can use Combine's @Published property wrapper (iOS 13+)—it’s way more straightforward than NotificationCenter for this use case. Here’s how it works:
// First, update your CustomModel to use Combine import Combine class CustomModel { // Mark variables you want to observe with @Published @Published var userName: String = "" @Published var score: Int = 0 } // In a child VC, accept the shared model and subscribe to changes class ChildVC1: UIViewController { // Hold a reference to the shared model (force-unwrap is safe here since we'll set it before VC loads) var sharedModel: CustomModel! private var cancellables = Set<AnyCancellable>() override func viewDidLoad() { super.viewDidLoad() // Subscribe to changes in userName sharedModel.$userName .sink { [weak self] newName in // Update your UI or run logic when the value changes self?.nameLabel.text = newName } .store(in: &cancellables) // Do the same for score or other variables sharedModel.$score .sink { [weak self] newScore in self?.scoreLabel.text = "Score: \(newScore)" } .store(in: &cancellables) } // When you need to update the model from the child VC func updateUserName(_ newName: String) { sharedModel.userName = newName } } // In your main VC, create the model and pass it to each child class MainVC: UIViewController { let customModel = CustomModel() override func viewDidLoad() { super.viewDidLoad() // Initialize each child VC and inject the model let child1 = ChildVC1() child1.sharedModel = customModel // Add child1 to your container view hierarchy... let child2 = ChildVC2() child2.sharedModel = customModel // Add child2 to your container... let child3 = ChildVC3() child3.sharedModel = customModel // Add child3 to your container... } }
If you’re targeting iOS versions before 13, or just prefer a more traditional approach, NotificationCenter works too. You’ll post a notification whenever the model’s variables change, and each child VC listens for that notification.
// Update your CustomModel to post notifications on change class CustomModel { var userName: String = "" { didSet { // Send a notification with the new value NotificationCenter.default.post( name: NSNotification.Name(rawValue: "CustomModelUserNameChanged"), object: self, userInfo: ["newUserName": userName] ) } } } // In a child VC, listen for the notification class ChildVC1: UIViewController { var sharedModel: CustomModel! override func viewDidLoad() { super.viewDidLoad() // Register to listen for the notification NotificationCenter.default.addObserver( self, selector: #selector(userNameChanged(_:)), name: NSNotification.Name(rawValue: "CustomModelUserNameChanged"), object: sharedModel ) } @objc func userNameChanged(_ notification: Notification) { // Extract the new value from the notification if let newName = notification.userInfo?["newUserName"] as? String { nameLabel.text = newName } } // Don't forget to remove the observer when the VC is deinitialized deinit { NotificationCenter.default.removeObserver(self) } } // Again, pass the shared model from MainVC to each child like in the first example
If you don’t want to pass the model around every time, you can make your CustomModel a singleton—this creates one global instance that all VCs can access directly. Just be careful: singletons stay in memory for the app’s entire lifecycle, which can lead to unexpected issues (like retaining unused objects) and make testing harder.
class CustomModel { // Singleton instance static let shared = CustomModel() // Private initializer to prevent creating other instances private init() {} var userName: String = "" { didSet { // Use Combine or NotificationCenter here to notify changes, same as before } } } // In any child VC, access the model directly class ChildVC1: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Read the model's value nameLabel.text = CustomModel.shared.userName // Update the model's value CustomModel.shared.userName = "New Name" } }
Search Keywords to Explore More
If you want to dive deeper into these concepts, search for:
- Swift dependency injection view controllers
- Swift shared model between view controllers
- Combine @Published view controller communication
- NotificationCenter Swift pass data between view controllers
- Code-only Swift view controller data sharing
内容的提问来源于stack exchange,提问作者Jim

