The release crashes after the ViewController is created

Problem Description

When working on a project, I encountered a crash problem. Looking at the code logic, I found that the following code would cause a crash.

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

Yes, you are not mistaken, the above code will cause a crash, 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 crashed is:

__weak TestTableViewController *weakSelf = self;

The first feeling I see here is very unexpected, because the calling place is only init an instance, and then the instance as a temporary variable in the method should be automatically released, so - (void)viewDidLoadthe code in the method should not be called .
However, TestTableViewController, as a subclass of UITableViewController - (void)dealloc, triggers the - (void)viewDidLoadmethod when the self.tableView of the parent class is accessed in the method.
Subsequently, __weak TestTableViewController *weakSelf = self;it crashed when executing the code.

The error log is on the iOS8.4 version of the simulator EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0).
Then I found that the problem does not flash back in the iOS10 system, but only a warning problem is output 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 calling place is like this:

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

        }];
    }];
}

Dismiss immediately after present shows vc, so there will be no flashback problem.
That is to say, as long as the viewDidLoad method of TestTableViewController has been executed, the viewDidLoad method will not be triggered during dealloc.

Solution

There are three conditions for this problem:
1. deallocThe tableView property of the parent class is accessed in the method.
2. The viewDidLoadweakSelf variable is defined in the method.
3. The instance variable of TestTableViewController is created, but it is not used.

Of the above three conditions, the first two are requirements of business logic. Generally speaking, they cannot be avoided. Therefore, the third condition can only be avoided as much as possible, namely: an instance of ViewController.
such as:

- (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];
}

Try to use the showWithType2 method instead of showWithType to avoid unpredictable crash problems.

Demo code

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

Guess you like

Origin blog.csdn.net/jhq1990/article/details/55669510