多层模态返回RootVC后调用UICollectionView.reloadData报错求助
Hey there, let's work through this issue step by step!
Your navigation flow looks like this:RootVC → modalView1 → modalView2 → modalView3
When you dismiss directly from modalView3 back to RootVC using this code:
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
The dismissal itself works fine, but calling collectionView.reloadData() (where the collection view lives in RootVC) throws an "unrecognized selector sent to instance" error, as shown in your screenshot.
Why This Happens
There are a few common culprits here:
- Invalid/Deallocated Collection View Reference: Your
collectionViewinstance inRootVCmight have been released from memory by the time you try to callreloadData(), or you're referencing it through a broken pointer. - Timing Mismatch: If you're calling
reloadData()before the dismissal completes,RootVC(or its collection view) might not be fully ready to handle UI updates yet. - Unsafe Force-Unwrapping: Using
!onself.view.windowcan lead to unexpected behavior if the window is nil, though this is less likely to cause the selector error directly.
Fixes to Try
1. Reload Safely in the Dismissal Completion Block
The best approach is to trigger the reload after the dismissal is fully done, and ensure you're referencing a valid RootVC instance:
// Inside modalView3 if let rootVC = self.view.window?.rootViewController as? RootViewController { self.view.window?.rootViewController?.dismiss(animated: true) { // Always run UI updates on the main thread! DispatchQueue.main.async { rootVC.collectionView.reloadData() } } }
This way, you know RootVC is active and its collection view is accessible once the dismissal finishes.
2. Verify RootVC Isn't Being Deallocated
Add a deinit method to your RootVC to check if it's being released unexpectedly:
// Inside RootViewController deinit { print("RootVC was deallocated!") }
If you see this print when dismissing from modalView3, that means RootVC is being removed from memory—this shouldn't happen since it's your root view controller, but if it does, you'll need to check for memory management issues in your modal presentation flow.
3. Use Notification Center for Decoupled Reload
If you don't want to directly reference RootVC from modalView3, use a notification to trigger the reload:
- In
RootViewController:
override func viewDidLoad() { super.viewDidLoad() // Register to listen for the reload notification NotificationCenter.default.addObserver( self, selector: #selector(reloadCollectionView), name: NSNotification.Name("ReloadRootCollectionView"), object: nil ) } @objc private func reloadCollectionView() { DispatchQueue.main.async { self.collectionView.reloadData() } } deinit { // Clean up the observer to avoid memory leaks NotificationCenter.default.removeObserver(self) }
- In
modalView3:
self.view.window?.rootViewController?.dismiss(animated: true) { // Post the notification after dismissal completes NotificationCenter.default.post( name: NSNotification.Name("ReloadRootCollectionView"), object: nil ) }
This keeps your view controllers decoupled, which is a cleaner pattern for cross-VC communication.
4. Ditch Force-Unwrapping
Replace self.view.window! with optional binding (like in the first fix) to avoid crashes if the window is ever nil. Force-unwrapping is risky and can lead to unexpected failures.
Final Tip
The selector error almost always means you're trying to call a method on an object that no longer exists (or never existed properly). Using the completion block to trigger the reload, along with a safe cast to RootVC, should resolve this by ensuring you're working with a valid, alive collection view instance.
内容的提问来源于stack exchange,提问作者Creign

