一、スレッド使用上の注意点(必須)
- 同時に多数のスレッドを開かない(1~3スレッド程度、5を超えないこと)
- スレッドの概念
メインスレッド:UIスレッド。UIの表示・更新、UIコントロールのイベント処理を行う サブスレッド:バックグラウンドスレッド、非同期スレッド
- 時間のかかる操作はメインスレッドで実行せず、サブスレッドで実行する
二、NSThread(必須)
- スレッドの作成と開始の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];
- 主なメソッド
現在のスレッドを取得
+ (NSThread *)currentThread;
メインスレッドを取得
+ (NSThread *)mainThread;
スレッドを一時停止
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
スレッド名を設定
- (void)setName:(NSString *)n;
- (NSString *)name;
三、スレッド同期(必須)
-
実質:複数スレッドが同じリソースを同時にアクセスすることによるデータの安全性問題を防ぐため
-
実装:コードに相互排他ロック(同期ロック)を適用
@synchronized(self) {
// ロックされたコード
}
四、GCD(Grand Central Dispatch)
- キューとタスク
タスク:実行する操作
- ブロックでタスクをカプセル化
キュー:タスクを格納する
- グローバルな並列キュー:タスクを並列実行できる
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();
- タスク実行の関数
同期実行:新しいスレッドを開始できない
dispatch_sync...
非同期実行:新しいスレッドを開始できる
dispatch_async...
- 一般的な組み合わせ(必須)
dispatch_async + グローバルな並列キュー dispatch_async + 作成した直列キュー
- スレッド間通信(必須)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 時間のかかる非同期操作を実行...
dispatch_async(dispatch_get_main_queue(), ^{
// メインスレッドに戻り、UI更新操作を実行
});
});
- GCDの全APIはlibdispatch.dylibにあり、Xcodeが自動的にインポートする
メインヘッダファイル:
#import <dispatch/dispatch.h>
- 遅延実行(必須)
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秒後に実行するタスク
});
- 一度だけ実行するコード(必須)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// このコードはプログラム実行中に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
- 非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
- キューの種類
メインキュー
- [NSOperationQueue mainQueue]
- "メインキュー"に追加された操作はすべてメインスレッドで実行される
非メインキュー
- [[NSOperationQueue alloc] init]
- "非メインキュー"に追加された操作はすべてサブスレッドで実行される
- キューへのタスク追加
-
- (void)addOperation:(NSOperation *)op;
-
- (void)addOperationWithBlock:(void (^)(void))block;
- 一般的な使用方法
最大同時実行数の設定
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
キューのその他の操作
- すべての操作をキャンセル
- (void)cancelAllOperations;
-
すべての操作を一時停止 [queue setSuspended:YES];
-
すべての操作を再開 [queue setSuspended:NO];
- 操作間の依存関係(面接の質問)
- NSOperation間で依存関係を設定して実行順序を保証できる
- [operationB addDependency:operationA]; // 操作Bが操作Aに依存。操作Aが完了してから操作Bが実行される
- 相互依存はできない(例:AがBに依存し、BがAに依存)
- 異なるキューのNSOperation間で依存関係を作成できる
- スレッド間の通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1.時間のかかる操作を実行
// 2.メインスレッドに戻る
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
}];
七、他のスレッドからメインスレッドに戻る方法
- perform....
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
- GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
- NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
八、コンパイラ環境の判定:ARCかMRCか? #if __has_feature(objc_arc) // 現在のコンパイラ環境はARC
#else // 現在のコンパイラ環境はMRC
#endif
九、クラスの初期化メソッド
- +(void)load
- あるクラスが初めてOC実行時システム(メモリ)に読み込まれるときに呼び出される
- プログラム起動時に呼び出される
- プログラム実行中に1度だけ呼び出される
- +(void)initialize
- あるクラスが初めて使用されるとき(例:クラスのメソッドが呼び出されたとき)に呼び出される
- プログラム起動時に必ず呼び出されるわけではない
- プログラム実行中に1度だけ実行したい操作がある場合、その操作は+(void)loadメソッドに配置するのが最適
十、サードパーティフレームワークの使用に関するアドバイス
- サードパーティフレームワークを使用する目的
開発効率:迅速な開発、他人がカプセル化した1行のコードが自分で書いたN行に相当する この機能の最高の実装を使用するため
- サードパーティフレームワークが多すぎる場合の欠点(無視可)
管理、アップグレード、更新 サードパーティフレームームワークにバグがあり、作者の解決を待つ必要がある サードパーティフレームームワークの作者が不幸にも亡くなり、更新が停止する(潜在的なバグが解決されない) 感じ:自分があまりに弱い
-
例 ストリーミング:オンライン動画、オーディオの再生(ダウンロードしながら再生) オーディオ、ビデオファイルの形式を非常に深く理解する 各ビデオには独自のデコード方式(C/C++)がある
-
まとめ
巨人の肩に立ってプログラミングする 問題ないので、比較的安定したサードパーティフレームワークを積極的に使用する
十一、セルの画像ダウンロード
- 面接の質問
あるURLに対応する画像の重複ダウンロードをどう防ぐか
- "セル画像ダウンロードの考え方 – サンドボックスキャッシュあり"
SDWebImageのデフォルトのキャッシュ期間は?
- 1週間
SDWebImageの内部実装は?
- 授業PPTの"セル画像ダウンロードの考え方 – サンドボックスキャッシュあり"
- 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つの機能を持つ