在做項目時遇到一個閃退問題,查看代碼邏輯發現以下代碼會造成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創建後釋放閃退的全文介紹,希望對您學習和使用IOS應用開發有所幫助.【ViewController創建後釋放閃退】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!