iOSにおけるスレッド技術の基本

一、スレッド使用上の注意点(必須)

  1. 同時に多数のスレッドを開かない(1~3スレッド程度、5を超えないこと)
  2. スレッドの概念

メインスレッド:UIスレッド。UIの表示・更新、UIコントロールのイベント処理を行う サブスレッド:バックグラウンドスレッド、非同期スレッド

  1. 時間のかかる操作はメインスレッドで実行せず、サブスレッドで実行する

二、NSThread(必須)

  1. スレッドの作成と開始の3つの方法

作成してから開始

// 作成
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(processData:) object:nil];
// 開始
[thread start];

作成と開始を一度に行う

[NSThread detachNewThreadSelector:@selector(processData:) toTarget:self withObject:nil];

暗黙的な作成(自動開始)

[self performSelectorInBackground:@selector(processData:) withObject:nil];
  1. 主なメソッド

現在のスレッドを取得

+ (NSThread *)currentThread;

メインスレッドを取得

+ (NSThread *)mainThread;

スレッドを一時停止

+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

スレッド名を設定

- (void)setName:(NSString *)n;
- (NSString *)name;

三、スレッド同期(必須)

  1. 実質:複数スレッドが同じリソースを同時にアクセスすることによるデータの安全性問題を防ぐため

  2. 実装:コードに相互排他ロック(同期ロック)を適用

@synchronized(self) {
    // ロックされたコード
}

四、GCD(Grand Central Dispatch)

  1. キューとタスク

タスク:実行する操作

  • ブロックでタスクをカプセル化

キュー:タスクを格納する

  • グローバルな並列キュー:タスクを並列実行できる
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  • 作成した直列キュー:タスクを順次実行させる
dispatch_queue_t queue = dispatch_queue_create("com.example.queue", DISPATCH_QUEUE_SERIAL);
  • メインキュー:タスクをメインスレッドで実行させる
dispatch_queue_t queue = dispatch_get_main_queue();
  1. タスク実行の関数

同期実行:新しいスレッドを開始できない

dispatch_sync...

非同期実行:新しいスレッドを開始できる

dispatch_async...
  1. 一般的な組み合わせ(必須)

dispatch_async + グローバルな並列キュー dispatch_async + 作成した直列キュー

  1. スレッド間通信(必須)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   // 時間のかかる非同期操作を実行...
    
    
   dispatch_async(dispatch_get_main_queue(), ^{
       // メインスレッドに戻り、UI更新操作を実行
   });
});
  1. GCDの全APIはlibdispatch.dylibにあり、Xcodeが自動的にインポートする

メインヘッダファイル:

#import <dispatch/dispatch.h>
  1. 遅延実行(必須)

perform....

// 3秒後に現在のスレッドでselfのdownload:メソッドを自動的に呼び出し、パラメータ@"http://555.jpg"を渡す
[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];

dispatch_after....

// タスクを実行するキュー
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
double delay = 3; // 遅延秒数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
    // 3秒後に実行するタスク
});
  1. 一度だけ実行するコード(必須)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // このコードはプログラム実行中に1度だけ実行される
});

五、シングルトンパターン(遅延初期化方式)

  1. ARC(自動参照カウント)
@interface DataManager : NSObject
+ (instancetype)sharedManager;
@end


@implementation DataManager
// 唯一のシングルトンオブジェクトを保持
static id _instance;

+ (id)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

+ (instancetype)sharedManager
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
@end
  1. 非ARC(マニュアル参照カウント)
@interface DataManager : NSObject
+ (instancetype)sharedManager;
@end

@implementation DataManager
// 唯一のシングルトンオブジェクトを保持
static id _instance;

+ (id)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

+ (instancetype)sharedManager
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

- (oneway void)release {
    
}

- (id)retain {
    return self;
}

- (NSUInteger)retainCount {
    return 1;
}

- (id)autorelease {
    return self;
}
@end

六、NSOperationとNSOperationQueue

  1. キューの種類

メインキュー

  • [NSOperationQueue mainQueue]
  • "メインキュー"に追加された操作はすべてメインスレッドで実行される

非メインキュー

  • [[NSOperationQueue alloc] init]
  • "非メインキュー"に追加された操作はすべてサブスレッドで実行される
  1. キューへのタスク追加
    • (void)addOperation:(NSOperation *)op;
    • (void)addOperationWithBlock:(void (^)(void))block;
  1. 一般的な使用方法

最大同時実行数の設定

  • (NSInteger)maxConcurrentOperationCount;
  • (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

キューのその他の操作

  • すべての操作をキャンセル
  • (void)cancelAllOperations;
  • すべての操作を一時停止 [queue setSuspended:YES];

  • すべての操作を再開 [queue setSuspended:NO];

  1. 操作間の依存関係(面接の質問)
  • NSOperation間で依存関係を設定して実行順序を保証できる
  • [operationB addDependency:operationA]; // 操作Bが操作Aに依存。操作Aが完了してから操作Bが実行される
  • 相互依存はできない(例:AがBに依存し、BがAに依存)
  • 異なるキューのNSOperation間で依存関係を作成できる
  1. スレッド間の通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
    // 1.時間のかかる操作を実行
    
    // 2.メインスレッドに戻る
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        
    }];
}];

七、他のスレッドからメインスレッドに戻る方法

  1. perform....
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
  1. GCD
dispatch_async(dispatch_get_main_queue(), ^{

});
  1. NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    
}];

八、コンパイラ環境の判定:ARCかMRCか? #if __has_feature(objc_arc) // 現在のコンパイラ環境はARC

#else // 現在のコンパイラ環境はMRC

#endif

九、クラスの初期化メソッド

  1. +(void)load
  • あるクラスが初めてOC実行時システム(メモリ)に読み込まれるときに呼び出される
  • プログラム起動時に呼び出される
  • プログラム実行中に1度だけ呼び出される
  1. +(void)initialize
  • あるクラスが初めて使用されるとき(例:クラスのメソッドが呼び出されたとき)に呼び出される
  • プログラム起動時に必ず呼び出されるわけではない
  1. プログラム実行中に1度だけ実行したい操作がある場合、その操作は+(void)loadメソッドに配置するのが最適

十、サードパーティフレームワークの使用に関するアドバイス

  1. サードパーティフレームワークを使用する目的

開発効率:迅速な開発、他人がカプセル化した1行のコードが自分で書いたN行に相当する この機能の最高の実装を使用するため

  1. サードパーティフレームワークが多すぎる場合の欠点(無視可)

管理、アップグレード、更新 サードパーティフレームームワークにバグがあり、作者の解決を待つ必要がある サードパーティフレームームワークの作者が不幸にも亡くなり、更新が停止する(潜在的なバグが解決されない) 感じ:自分があまりに弱い

  1. 例 ストリーミング:オンライン動画、オーディオの再生(ダウンロードしながら再生) オーディオ、ビデオファイルの形式を非常に深く理解する 各ビデオには独自のデコード方式(C/C++)がある

  2. まとめ

巨人の肩に立ってプログラミングする 問題ないので、比較的安定したサードパーティフレームワークを積極的に使用する

十一、セルの画像ダウンロード

  1. 面接の質問

あるURLに対応する画像の重複ダウンロードをどう防ぐか

  • "セル画像ダウンロードの考え方 – サンドボックスキャッシュあり"

SDWebImageのデフォルトのキャッシュ期間は?

  • 1週間

SDWebImageの内部実装は?

  • 授業PPTの"セル画像ダウンロードの考え方 – サンドボックスキャッシュあり"
  1. SDWebImage

主なメソッド

- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;

メモリ処理:アプリがメモリ警告を受けたとき

/**
 *  アプリがメモリ警告を受けたとき
 */
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
    SDWebImageManager *mgr = [SDWebImageManager sharedManager];
    
    // 1.ダウンロード中の操作をキャンセル
    [mgr cancelAll];
    
    // 2.メモリキャッシュをクリア
    [mgr.imageCache clearMemory];
}

SDWebImageOptions

  • SDWebImageRetryFailed : ダウンロード失敗後、自動的に再ダウンロードする
  • SDWebImageLowPriority : UIのインタラクションが行われているとき、内部の一部ダウンロード操作を自動的に一時停止する
  • SDWebImageRetryFailed | SDWebImageLowPriority : 上記2つの機能を持つ

タグ: iOS スレッド GCD NSOperation シングルトン

5月25日 13:57 投稿