不创建新实例调用ViewController及通知重复执行问题
Hey there! Let's break down your problem step by step—you've got two main issues here: a retain cycle causing your hello() function to fire twice via notifications, and needing to call hello() when the app becomes active without running into those duplicates. Here's how to fix both:
1. Fix the Retain Cycle First (Root Cause of Duplicate Calls)
The core issue is that MainViewController holds a strong reference to MainTabBarController, while the tab bar controller already strongly references its child view controllers (including MainViewController) via its viewControllers array. This creates a retain cycle—neither controller can be deallocated properly, so if you register a notification in MainTabBarController, the old instance's listener sticks around when you navigate back/forth, leading to duplicate calls.
Fix this by making the reference in MainViewController weak:
class MainViewController: UIViewController { // Use weak to avoid strong reference to the parent tab bar controller weak var mainTabBarController: MainTabBarController? override func viewDidLoad() { super.viewDidLoad() // Safely cast the parent tab bar controller instead of holding a strong reference self.mainTabBarController = self.tabBarController as? MainTabBarController } }
Now the tab bar controller can deallocate normally when it's no longer needed, and its notification listeners will be cleaned up.
2. Properly Manage Notification Registration/Removal
Even with the retain cycle fixed, you need to ensure notifications are only registered once and removed when the controller is gone. Here's the clean way to handle this in MainTabBarController:
class MainTabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() // Register your custom notification NotificationCenter.default.addObserver( self, selector: #selector(hello), name: NSNotification.Name("YourCustomNotification"), // Replace with your actual notification name object: nil ) } deinit { // Remove ALL observers for this instance when it's deallocated NotificationCenter.default.removeObserver(self) } @objc func hello() { print("Hello called!") // Your existing logic here } }
The deinit method will now run thanks to the fixed retain cycle, ensuring no leftover notification listeners cause duplicate calls.
3. Call hello() When the App Becomes Active (Without Duplicates)
Instead of using a notification to trigger hello() from AppDelegate/SceneDelegate (which could overlap with your existing notification), directly call the method on the active MainTabBarController instance:
For iOS 12 and below (AppDelegate):
class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidBecomeActive(_ application: UIApplication) { // Grab the root tab bar controller safely guard let mainTabBarController = UIApplication.shared.keyWindow?.rootViewController as? MainTabBarController else { return } mainTabBarController.hello() } }
For iOS 13+ (SceneDelegate):
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func sceneDidBecomeActive(_ scene: UIScene) { guard let window = window, let mainTabBarController = window.rootViewController as? MainTabBarController else { return } mainTabBarController.hello() } }
This way, you're directly invoking the method without relying on notifications, so no risk of duplicate calls from overlapping event triggers.
Quick Recap
- Break the retain cycle with a weak reference in
MainViewController - Clean up notifications in
deinitto avoid leftover listeners - Directly call
hello()fromAppDelegate/SceneDelegateinstead of using notifications for that trigger
内容的提问来源于stack exchange,提问作者Kárpáti András

