Pop to root view controller without animation crash for the table view

后端 未结 6 1012
伪装坚强ぢ
伪装坚强ぢ 2021-02-05 19:27

I have 3 view controller in a tab bar controller. Clicking on any tab loads its root view controller in the navigation stack.

e.g. tab1, tab2, and tab3.
The 2nd vi

相关标签:
6条回答
  • 2021-02-05 20:03

    I consider this a bug or at least a weakness in UIKit, but I've already blown half my day on it, so I'm not going to write it up with example code and report it to Apple right now. If someone else wants to do that, I would appreciate it.

    Here's what I think is going on under the hood. You have a UITableViewController, let's call it myTable, on the stack of a UINavigationController, and that navigation stack is hidden because it's on an unselected tab or whatever. Then, you call [myTable.tableView reloadData], and iOS cleverly optimizes by not reloading the data right away, because the user won't be seeing it anyway if it's on a hidden tab. Instead, the reload request is deferred and stored somewhere for when the view is shown. But before it can be shown, you pop myTable off the navigation stack. When myTable's original tab is shown, the reload request gets executed, but its dataSource is no longer there, so it's a bad access.

    Now from my tests with a subclass of UITableViewController that uses the automatically provided tableView property (not loaded from a NIB file), the UITableView is not being deallocated when myTable deallocates as in the situation above. That would be fine, except the default dealloc implementation for UITableViewController does not clear the dataSource property of the UITableView (which was set by the default implementation of init).

    So, there are probably a couple good workarounds, like deferring the request to reloadData yourself, but the simplest one I can think of is putting this in the implementation of your UITableViewController subclass:

    - (void)dealloc {
      ...
      self.tableView.delegate = nil;
      self.tableView.dataSource = nil;
      [super dealloc];
    }
    

    Any additional wisdom would be most welcome.

    0 讨论(0)
  • 2021-02-05 20:05

    While Jesse's answer provided insight into the semantics around this problem, in my case the underlying cause was different. Just thought I'd mention it in case someone finds himself in the same situation.

    I was seeing the error message

    * -[UIAnimator removeAnimationsForTarget:]: message sent to deallocated instance ...

    where the object in question was a UITableViewCell. On inspection, there were no memory allocation issues in my code.

    The problem turned out to be that I was calling one of the popViewController:animated: family of methods from a non-UI thread. This thread had been created to run some network operations and database processing tasks. I simply moved the invocation of the pop method to the UI thread and found that I stopped getting the error.

    0 讨论(0)
  • 2021-02-05 20:07

    Had a similar problem and Im pretty sure it has something to do with the new SDK to be honest. The following code worked fine before. I have one navigationcontroller and a new one pushed on to that with 3 different views that gets put onto it (Think: changing password where you have 3 different steps: control, change, repeat.) If the user types the wrong password you will first be pushed of the "changing password controller" and then be pushed to the first page (logged out).

    This worked before:

    -(void)logout {
        [self.presentedViewController dismissModalViewControllerAnimated:TRUE];
    
        self.localNavigationController = nil;
    
        [self.navigationController popToRootViewControllerAnimated:TRUE];
     }
    

    The way you could solve this is by change ViewWillAppear to ViewDIDAppear. You might have some lagg but atleast it doesnt crash :)

    0 讨论(0)
  • 2021-02-05 20:08

    You can try this to avoid the problem:

    -(void)viewWillAppear:(BOOL)animated
    {
       if (animated)
       {
          [self.tableView reloadData];
       }
    }
    

    When navigating from a tab bar controller, the view will not be animated. So if the view is appearing just for an instant before popping to the root, it won't attempt to reload the table data.

    0 讨论(0)
  • 2021-02-05 20:21

    Jesse's answer works perfect. I just made a slight modification for ARC Support

    - (void)dealloc 
    {
      self.tableView.delegate = nil;
      self.tableView.dataSource = nil;
    }
    
    0 讨论(0)
  • 2021-02-05 20:27

    Double-click your executable in the Groups&Files list; click Arguments tab; click "+" in lower pane, enter "NSZombieEnabled", set value to YES, check the box, click red dot to dismiss. Now run your test case again, and it will tell you which object has been deallocated. I suspect it's the array backing your tableView in tab2V2. Make sure your memory handling is correct (is it retained and released correctly?).

    0 讨论(0)
提交回复
热议问题