ViewController创建后释放闪退
来源:互联网 发布:c语言 小数比大小 编辑:程序博客网 时间:2024/04/29 11:17
问题描述
在做项目时遇到一个闪退问题,查看代码逻辑发现以下代码会造成crash。
- (IBAction)buttonTouchUpInside:(id)sender { TestTableViewController *vc = [[TestTableViewController alloc]init];}
是的,你没有看错,上面的代码会造成闪退,TestTableViewController的代码如下:
TestTableViewController.h文件
#import <UIKit/UIKit.h>@interface TestTableViewController : UITableViewController@end
TestTableViewController.m文件
#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
出现闪退的代码是:
__weak TestTableViewController *weakSelf = self;
我看到这里的第一感觉是很意外,因为调用的地方只是init了一个实例,随后该实例作为方法中的临时变量应该就自动释放了,所以不应该会调用到- (void)viewDidLoad
方法中的代码。
但是,TestTableViewController作为UITableViewController的子类,当在- (void)dealloc
方法中,访问父类的self.tableView时,就触发了- (void)viewDidLoad
方法。
随后,在执行__weak TestTableViewController *weakSelf = self;
代码时闪退。
在iOS8.4版本的模拟器上错误日志是EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)
。
而后我发现该问题在iOS10系统中并不会闪退,而只是在运行时输出一个warning问题:
[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>)
但是,如果调用的地方是这样的:
- (IBAction)buttonTouchUpInside:(id)sender { TestTableViewController *vc = [[TestTableViewController alloc]init]; [self presentViewController:vc animated:YES completion:^{ [vc dismissViewControllerAnimated:YES completion:^{ }]; }];}
present显示vc后马上dismiss掉,这样并不会出现闪退问题。
也就是说只要TestTableViewController的viewDidLoad方法执行过,那么在dealloc的时候便不会再触发viewDidLoad方法。
解决方法
该问题发生有三个条件:
1、在dealloc
方法中访问了父类的tableView属性。
2、在viewDidLoad
方法中定义了weakSelf变量。
3、创建了TestTableViewController的实例变量,但又没有使用。
以上三个条件,前两个都是业务逻辑的要求,一般来说无法避免,所以只能尽可能避免第3个条件的出现,即:ViewController的实例,如果用不到就不要创建。
比如:
- (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];}
尽量使用showWithType2方法的写法,而不是showWithType,以免出现不可预测的闪退问题。
演示代码
https://code.csdn.net/jhq1990/demo2017-02-18/
- ViewController创建后释放闪退
- 动态创建的viewcontroller被自动释放,引起EXC_BAD_ACCESS
- eclipse 启动后,闪退
- eclipse 启动后,闪退
- eclipse 启动后,闪退
- eclipse 启动后,闪退
- eclipse 启动后,闪退
- //创建的HDC 释放后无法释放内存解决方法
- 为何ViewController释放后不走dealloc
- 为何ViewController释放后不走dealloc
- 为何ViewController释放后不走dealloc
- 为何ViewController释放后不走dealloc
- 为何ViewController释放后不走dealloc
- eclipse 强行关闭后一直闪退
- Xamarin破解后出现闪退处理
- Xamarin破解后出现闪退处理
- Eclipse异常关闭后启动闪退
- eclipse崩溃后 打不开一直闪退
- HDU 2255 (KM算法)
- JavaScript之Cookie/Session机制详解04之区别
- Filter/滤波器
- 1184
- swift中函数中定义函数的功能
- ViewController创建后释放闪退
- eclipse工作空间配置--------加载Tomcat服务器
- Canvas
- App优化之提升你的App启动速度之实例挑战
- Android 基于第三方登录(使用Bmob后端云存储数据)实现记忆用户登录、不必重复登录
- Linux学习篇------vim程序编辑器
- Caffe 数据集制作及使用
- oracle中的sqlnet.ora tnsnames.ora listener.ora三个文件
- kettle闪退问题