關於iOS刷新UI需要在主線程執行


為什么一定要在主線程刷新UI?
安全+效率:因為UIKit框架不是線程安全的框架,當在多個線程進行UI操作,有可能出現資源搶奪,導致問題。

其實:在子線程是不能更新UI的, 看到能更新的結果只是個假象。因為:在子線程代碼完成之后,回到主線程,然后執行了子線程的更新UI的代碼,由於這個時間很短,所以看起來是能夠在子線程刷新UI的。想驗證的話也很簡單,看下面demo:點擊按鈕,會開啟一個子線程,然后在子線程中刷新該按鈕的標題,再新建一個按鈕,最后一行代碼是延遲5秒。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.button];   
}

-(UIButton *)button{
    if (!_button) {
        _button = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, SCREEN_WIDTH, 100)];
        _button.backgroundColor = [UIColor yellowColor];
        [_button addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
        [_button setTitle:@"UI" forState:UIControlStateNormal];
        [_button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
        _button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
        _button.titleLabel.font = [UIFont systemFontOfSize:13];
    }
    return _button;
}

- (void)btnClicked {
    [NSThread detachNewThreadSelector:@selector(uiRefreashTest) toTarget:self withObject:nil];
}

- (void)uiRefreashTest {
    NSLog(@"當前線程:%@", [NSThread currentThread]);
    NSLog(@"主線程:%@", [NSThread mainThread]);
    
    //在子線程刷新該按鈕的標題名字為子線程信息
    NSString *subStr = [NSString stringWithFormat:@"子線程:%@", [NSThread currentThread]];
    NSString *mainStr = [NSString stringWithFormat:@"主線程:%@", [NSThread mainThread]];
    [_button setTitle:subStr forState:UIControlStateNormal];
    CGRect labelTitleSize = [subStr boundingRectWithSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil];
    _button.frame = CGRectMake(0, 100, labelTitleSize.size.width+10, labelTitleSize.size.height+10);
    
    //在子線程新建一個按鈕,標題名字為主線程信息
    UIButton *newBtn = [[UIButton alloc] init];
    newBtn.backgroundColor = [UIColor greenColor];
    newBtn.titleLabel.font = [UIFont systemFontOfSize:13];
    newBtn.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
    [newBtn setTitle:mainStr forState:UIControlStateNormal];
    [newBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    CGRect labelTitleSize01 = [mainStr boundingRectWithSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil];
    
    newBtn.frame = CGRectMake(0, 250, labelTitleSize01.size.width+10, labelTitleSize01.size.height+10);
    [self.view addSubview:newBtn];
    
    //在這個子線程延遲5秒鍾
    sleep(5);
}

  

執行結果:

 
333.gif

結果分析:
從圖中點擊按鈕后,雖然任務是在同一個子線程執行,但是並沒有按順序執行,而是首先立即執行NSLog日志輸出,但是接下來並沒有執行刷新按鈕標題,和新建按鈕的代碼,而是優先執行sleep(5)延遲代碼,然后才執行的刷新和新建控件的代碼

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
轉自簡書
作者:wg剛
鏈接:https://www.jianshu.com/p/8d0aa880d55b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM