1. 程式人生 > >iOS經典講解之多執行緒應用場景

iOS經典講解之多執行緒應用場景

<pre name="code" class="objc">   通過下面一個例子來了解一下多執行緒的應用場景,我們可以通過點選按鈕來開始或者暫停動畫的播放,但是當我們點選另一個按鈕時,
就會執行一個方法,在該方法中迴圈列印一個很大的數字,在列印過程中,再通過點選播放/暫停按鈕來控制動畫已經無法做到了
,這時螢幕已經卡死,必須等待列印完成,才能控制動畫的播放。如何既能列印又能控制動畫的播放那,可以利用多執行緒來完成,
將列印交給子執行緒去完成就可以了,下面講了幾種簡單開啟的子執行緒方法,非常詳細。在進入例子之前先來了解一下執行緒的基礎知識。
<pre name="code" class="objc">/**
 *  程序:一個正在執行的程式,叫一個程序
    多程序:多個程式正在執行,叫多程序
    執行緒:一個程式或者說一個程序 都會有一個或多個執行緒 如果只有一個 我們叫他主執行緒 主執行緒負責使用者能看見的任務 例如新增控制元件 重新整理頁面,除了主執行緒以外
都叫子執行緒, 執行緒之間是獨立的沒有任何聯絡,子執行緒一般負責使用者不直接看到的任務 例如載入圖片的過程 下載視訊等。
 執行緒要明確的:只要使用者看得見的 或者 跟使用者看得見有關的 都使用主執行緒 進行操作。 因為開啟子執行緒操作的時候 是為了更好地使用者體驗 
使用者體驗直接的表現為看到的或者點選的流暢性。
 執行緒是耗費資源的,雖然可以多執行緒操作 可以提高使用者體驗 但是不建議 進行很多執行緒同時進行操作。
 */

#import "RootViewController.h"

@interface RootViewController ()

// 宣告一個imageView
@property (nonatomic, retain) UIImageView *imageView;

@end

@implementation RootViewController



-(void)dealloc
{
    [_imageView release];
    [super dealloc];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self addSubviews];

}

// 建立imageView並新增圖片按鈕
- (void)addSubviews
{
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 200, 200)];
    self.imageView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.imageView];
    [_imageView release];
    
    // 播放一組圖片
    NSMutableArray *imageArray = [NSMutableArray array];
    for (int i = 0; i < 3; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"pic%d", i + 4]];
        // 加進陣列
        [imageArray addObject:image];
    }
    // 設定播放屬性
    self.imageView.animationImages = imageArray;
    self.imageView.animationDuration = 0.5;
    self.imageView.animationRepeatCount = 0;
    
    // 點選按鈕 開始播再點選按鈕停止播
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(100, 320, 50, 50);
    button.backgroundColor = [UIColor blueColor];
    [button setTitle:@"播放" forState:UIControlStateNormal];
    [button setTitle:@"停止" forState:UIControlStateSelected];
    [button addTarget:self action:@selector(actionButton:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    
    // 點選另一個按鈕 迴圈列印
    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    button1.frame = CGRectMake(160, 320, 50, 50);
    button1.backgroundColor = [UIColor blueColor];
    [button1 setTitle:@"列印" forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(actionPrint:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button1];
    
    //需要一邊列印 一邊還能 開關動畫
    // 解決方案:開啟一個子執行緒去完成列印的工作
#pragma mark ----NSThread----
    // 這是一個最輕量級的執行緒 可以開啟執行緒和關閉執行緒
    // 建立一個執行緒 就是給他一個方法去執行
    // 建立一個子執行緒專門去列印
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(actionPrint:) object:nil];
    // 開啟這個執行緒
   [thread start];
    // 注意:執行緒操作的時候
    // 在主執行緒的時候 系統自動添加了一個 自動釋放池 那麼咱們在開啟子執行緒的時候 也要新增一個自動釋放池
    // 如果你的執行緒開的比較多 會造成程式碼比較亂 閱讀性不高
    // 一般方法中 添加了自動釋放池 基本上都是執行緒方法
    
#pragma mark ---NSObject
    //NSObject也提供了開啟執行緒的方法 也可以解決程式卡死問題
    [self performSelectorInBackground:@selector(actionPrint:) withObject:nil];
    //NSOperation也是抽象類 沒有實現具體功能
    //NSInvocationOperation 呼叫操作(相當於任務)
    //NSBlockOperation block操作(相當於任務)
    //NSOperationQueue 執行緒佇列
    //建立任務一
    NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation1) object:nil];
    
    // 建立任務二
    NSBlockOperation *blockOP2 = [NSBlockOperation blockOperationWithBlock:^{
        // block 塊中 就相當於添加了任務
        [self blockOP2];
    }];
    
    // 建立一個佇列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 注意 新增任務前要設定依賴關係
    // 依賴性(序列)
    [invocation addDependency:blockOP2]; // 前面完成 後面才能開始
    // 把任務新增到隊列當中
    [queue addOperation:invocation];
    [queue addOperation:blockOP2];
    // 設定執行緒最大併發數
    queue.maxConcurrentOperationCount = 2;
    
    // 需求 進行同步請求一張圖片 不產生螢幕卡頓
    // 思路:開啟一個子執行緒 進行同步請求圖片 圖片載入完成後回到主執行緒 顯示到imageView上
    
}
// 實現任務一
- (void)invocation1
{
    // 子執行緒中新增一個自動釋放池
    @autoreleasepool {
    //[NSThread currentThread] 當前執行緒的資訊
    //列印是否是主執行緒
    // 打印出來的number 是執行緒的個數 第幾個執行緒
    NSLog(@"%@ 是不是主執行緒:%d", [NSThread currentThread], [NSThread isMainThread]);
        
    }
}
// 建立任務二
- (void)blockOP2
{
    @autoreleasepool {
        
    NSLog(@"%@ 是不是主執行緒:%d", [NSThread currentThread], [NSThread isMainThread]);
        
    }
}
// 點選按鈕 開始播再點選按鈕停止播
- (void)actionButton:(UIButton *)button
{
    button.selected = !button.selected;
    if (button.selected == YES) {
        
        [self.imageView startAnimating];

    } else {
        
        [self.imageView stopAnimating];
    }
}

// 迴圈列印 卡死程式
- (void)actionPrint:(UIButton *)button
{
    // 新增一個自動釋放池
    
    @autoreleasepool {
       for (int i = 0; i < 888888888; i++) {
        NSLog(@"%d", i);
    }
}
}

@end