iOS經典講解之多執行緒應用場景
阿新 • • 發佈:2018-12-30
<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