你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> ViewController創建後釋放閃退

ViewController創建後釋放閃退

編輯:IOS開發綜合

問題描述

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

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved