iOSアプリ開発で画面のフリーズを抑止する方法

ユーザのUI画面へのアクションで、時間を要する処理(例:通信処理、DB処理)を実行すると、処理が完了するまで画面がユーザの操作を受け付けなくなる。この状態は良いユーザビリティとは言えない。
今回はiOSアプリ開発で画面のフリーズを抑止する方法を紹介する。

<方法概要>
マルチスレッド処理を実装し、時間を要する処理をメインスレッドとは別のスレッドで実行することで、画面がフリーズする事を抑止する。
Objective-Cでマルチスレッドを実装する方法は複数あるが、今回は「GCD(Grand Central Dispatch)」を使用する方法を紹介する。

<方法詳細>
GCDでマルチスレッド処理を行うには、キューを準備する必要がある。「メインスレッド用のキュー」と「別スレッド用のキュー」の2つを広域変数として定義しておくと便利である。
メインスレッド用のキューは「dispatch_get_main_queue」で取得し、別スレッド用のキューは「dispatch_queue_create」で作成する。
実際に別スレッドの処理を記述するには、「dispatch_async」を使用して行う。第1引数にキューを指定し、第2引数にブロックとして処理を記述する。

サンプルコードを下記に示す。

<サンプルコード>

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController{
    
    //メインスレッド用のキューを定義
    dispatch_queue_t main_queue;
    
    //別スレッド用のキューを定義
    dispatch_queue_t other_queue;
}

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //メインスレッド用のキューを取得する
    main_queue  = dispatch_get_main_queue();
    
    //別スレッド用のキューを作成する(第1引数は任意の文字列、第2引数は0固定)
    other_queue = dispatch_queue_create("lab.moonmt.multi", 0);
}

- (IBAction)tapBtn{
    
    NSLog(@"メソッド開始");
    
    //別スレッド処理を本ブロック内に記述する
    dispatch_async(other_queue, ^{
        
        //時間を要する処理を以下に記述する
        
        NSLog(@"別スレッドで処理開始");
        
        //↓↓↓ 例として時間を要する意味の無い処理を実行 ↓↓↓
        NSString *buf = @"";
        for(int i=0; i<20000; i++){
            
            buf = [buf stringByAppendingString:@"abcdefg"];
        }
       //↑↑↑ 例として時間を要する意味の無い処理を実行 ↑↑↑
        
        //画面に結果を返却する場合はメインスレッド上で行う必要がある
        dispatch_async(main_queue, ^{
            
            //別スレッドの処理結果を画面に表示する処理を記述する
            
            NSLog(@"処理完了");
            label.text = @"処理完了";
        });
        
        NSLog(@"別スレッドで処理終了");
    });
    
    NSLog(@"メソッド終了");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

<実行結果>

2014-11-26 20:55:37.389 MultiThreadSample[10529:72780] メソッド開始
2014-11-26 20:55:37.390 MultiThreadSample[10529:72780] メソッド終了
2014-11-26 20:55:37.390 MultiThreadSample[10529:72841] 別スレッドで処理開始
2014-11-26 20:55:59.760 MultiThreadSample[10529:72780] 処理完了
2014-11-26 20:55:59.760 MultiThreadSample[10529:72841] 別スレッドで処理終了

(下の2行の出力順序が入れ替わる場合もあるが正常に動作している)

<考察>
ログの出力順序を確認すると、別スレッドで処理を終了するより前に「メソッド終了」(2行目)のログが出力されている。
また、NSLogの[]内のコロンより後ろの数値は、スレッドIDを表すが、別スレッドで実行しているログ出力のIDがメインスレッドとは別のIDとなっていることが確認できる。
マルチスレッド処理を実装しなければ、37秒から59秒まで(1行目から5行目の間)の約22秒間画面がフリーズした状態になるが、マルチスレッド処理を実装したことにより、画面がフリーズするのは0.01秒(1行目と2行目の間)となり、ユーザに意識されることはなくなった。

Enjoy Programing!!

<お勧め書籍>

詳解 Objective-C 2.0 第3版
iOSアプリ開発技術者として仕事をするのであれば、必ず読んでおくべき書籍である。
筆者も何度も繰り返し精読している。