Release Flash after ViewController Creation

Keywords: iOS simulator

Problem description

When you are working on a project, you encounter a flashback problem. Looking at the code logic, you can see that the following code causes crash.

- (IBAction)buttonTouchUpInside:(id)sender {
    TestTableViewController *vc = [[TestTableViewController alloc]init];
}

Yes, you did not read it wrong. The code above will cause flip-flop. The code of TestTableViewController is as follows:
TestTableViewController.h file

#import <UIKit/UIKit.h>

@interface TestTableViewController : UITableViewController

@end

TestTableViewController.m file

#import "TestTableViewController.h"

@interface TestTableViewController ()

@end

@implementation TestTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    __weak TestTableViewController *weakSelf = self;

    [self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentOffset"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"%@",change);
}

@end

The code that flashes back is:

__weak TestTableViewController *weakSelf = self;

The first thing I saw here was a surprise, because the invocation was just an instance of init, which should then be automatically released as a temporary variable in the method, so the code in the -(void)viewDidLoad method should not be invoked.
However, TestTableViewController, as a subclass of UITableViewController, triggers the -(void)viewDidLoad method when accessing the self.tableView of the parent class in the -(void)dealloc method.
Subsequently, flip back when executing _weak TestTableViewController * weak Self = self; code.

The error log on the iOS 8.4 simulator is EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0).
Then I found out that this problem will not flip back in iOS 10 system, but only output a warning problem at runtime:

[Warning] Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<TestTableViewController: 0x7fe85fc01790>)

However, if the call is made in such a way:

- (IBAction)buttonTouchUpInside:(id)sender {
    TestTableViewController *vc = [[TestTableViewController alloc]init];
    [self presentViewController:vc animated:YES completion:^{
        [vc dismissViewControllerAnimated:YES completion:^{

        }];
    }];
}

present will be dismiss ed immediately after the vc is displayed, so there will be no flicker problem.
That is to say, as long as the viewDidLoad method of TestTableViewController has been executed, the viewDidLoad method will not be triggered at dealloc.

Solution

There are three conditions for this problem to occur:
1. The tableView property of the parent class is accessed in the dealloc method.
2. Define weakSelf variable in viewDidLoad method.
3. Create instance variables of TestTableViewController, but they are not used.

The first two of the above three conditions are the requirements of business logic. Generally speaking, they are unavoidable, so the third condition can only be avoided as far as possible, that is, the instance of ViewController should not be created if it is not needed.
For example:

- (void)showWithType:(NSInteger)type {
    TestTableViewController *vc = [[TestTableViewController alloc]init];
    if (type==1) {
        vc.title = @"1";
    } else if (type==2) {
        vc.title = @"2";
    } else {
        return;
    }
    [self presentViewController:vc animated:YES completion:nil];
}

- (void)showWithType2:(NSInteger)type {
    NSString *title;
    if (type==1) {
        title = @"1";
    } else if (type==2) {
        title = @"2";
    } else {
        return;
    }
    TestTableViewController *vc = [[TestTableViewController alloc]init];
    vc.title = title;
    [self presentViewController:vc animated:YES completion:nil];
}

Use the showWithType2 method instead of showWithType to avoid unpredictable flicker problems.

Demo code

https://code.csdn.net/jhq1990/demo2017-02-18/

Posted by Barnacles on Sun, 31 Mar 2019 11:27:28 -0700