Skip to content

Instantly share code, notes, and snippets.

@sahara-ooga
Last active May 23, 2017 06:34
Show Gist options
  • Save sahara-ooga/fa568f341e965bbeefcfd9af16d4c449 to your computer and use it in GitHub Desktop.
Save sahara-ooga/fa568f341e965bbeefcfd9af16d4c449 to your computer and use it in GitHub Desktop.
Swift・Objective-Cにおける非同期処理・blockの扱い

非同期処理

GCD

ディスパッチキューの種類

名前 説明
直列ディスパッチキュー serial dispatch queue 現在実行中の処理の終了を待ってから、次の処理を実行する
並列ディスパッチキュー concurrent dispatch queue 現在実行中の処理の終了を待たずに次の処理を並列で実行する

ディスパッチキューの取得

ディスパッチキューを利用するには、既存のディスパッチキューを取得するか、新規のディスパッチキューを取得する。

既存のディスパッチキューの取得

名前 直列・並列 説明 取得方法
メインキュー main queue 直列 メインスレッドで処理を実行する let queue = DispatchQueue.main
グローバルキュー global queue 並列 現在実行中の処理の終了を待たずに次の処理を並列で実行する let queue = DispatchQueue.global(qos: .userInitiated)

グローバルキューは実行優先度 (qualiity of service、QoS)によって次の5種類がある:

  • userInteractice ユーザーからの入力に対してインタラクティブに実行され、即時に実行されなければフリーズしているように見える処理に用いる
  • userInitiated ユーザーからの入力を受けて実行される処理に用いる
  • default
  • utility 視覚的な情報の更新を伴いつつも即時の結果を要求しない処理に用いる
  • background バックアップなど、目に見えないところで行われ、数分〜数時間かかっても問題ない処理に用いる
参考:QoSの定義
public struct DispatchQoS : Equatable {

    public let qosClass: DispatchQoS.QoSClass

    public let relativePriority: Int

    public static let background: DispatchQoS

    public static let utility: DispatchQoS

    public static let `default`: DispatchQoS

    public static let userInitiated: DispatchQoS

    public static let userInteractive: DispatchQoS

    public static let unspecified: DispatchQoS

    public enum QoSClass {

        case background

        case utility

        case `default`

        case userInitiated

        case userInteractive

        case unspecified

        public init?(rawValue: qos_class_t)

        public var rawValue: qos_class_t { get }
    }

    public init(qosClass: DispatchQoS.QoSClass, relativePriority: Int)
}

新規のディスパッチキューの取得

let newQueue = DispatchQueue(
    label: "com.my_company.my_app.upload_queue",
    qos:.default,
    attributes:[.concurrent]//[]なら直列ディスパッチキューを作成,.concurrentを追加すると並列ディスパッチキューを取得
)

ディスパッチキューへのタスクの追加

DispatchQueue型のasync(execute:)メソッドを利用する。 タスクの追加方法は直列・並列で共通。

queue.async {
    print("非同期の処理")
}

その他のAPI

ここはMixiのトレーニングコースの引き写しなので、ObjCになりますがご了承くださいm(-_-)m。 なお、タスク同士の依存関係の定義や、条件に応じたタスクのキャンセルを実装する場合は、OperationクラスとOperationQueueクラスを検討のこと。

dispatch group

グループに追加したすべてのタスクが終わってから以下の処理を実行したい場合に使う。

例:

  dispatch_group_t group = dispatch_group_create(); // 1. dispatch group の生成

    for (NSInteger i = 0 ; i < 100; ++i) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        // 2. タスクをdispatch_queue に追加
        dispatch_group_async(group, queue, ^{
            NSLog(@"%d", i);
        });

    }

    // 3. タスクの終了まで待機
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"here!!");

    // 4. 不要になったgroupをrelease
    dispatch_release(group);

dispatch barrier async

排他的に非同期処理を行う。

例:

dispatch_queue_t queue = dispatch_queue_create("jp.mixi.ios.sample.barrier", DISPATCH_QUEUE_CONCURRENT);
NSMutableString *string = [NSMutableString string];

for (NSInteger i = 0 ; i < 100; ++i) {
    if (i % 10 == 0) { // 書き込み処理

        // barrier async
        dispatch_barrier_async(queue, ^{
            [string deleteCharactersInRange:NSMakeRange(0, string.length)];
            [string appendFormat:@"%02d", i];
        });

    } else { // 読み込み処理

        dispatch_async(queue, ^{
            NSLog(@"%02d : string = %@", i, string);
        });

    }
}

Operation、OperationQueueクラス

ここからSwiftに戻ります^^;

単純な非同期処理の場合、GCDを直接利用すべきだが、タスクのキャンセル、タスク間の依存関係を指定するにはOperationクラスを利用すべき。

Blocks

mixiのBlocksの解説が詳しいのでそちらをご覧ください。他に参考になったのは [Objective-C] Blocksがややこいのでまとめてみる ですね!

参考

//
// BlockSample.h
//
//
#import <Foundation/Foundation.h>
typedef void (^blk_t)();
@interface BlockSample : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) blk_t name_print_block;
@end
//
// BlockSample.m
//
//
#import "BlockSample.h"
@implementation BlockSample
- (id)init
{
self = [super init];
if (self) {
__weak BlockSample *weakSelf = self;
_name_print_block = ^{
NSLog(@"%@", weakSelf.name);
};
}
return self;
}
@end
#import <Foundation/Foundation.h>
@interface NSArray (grep)
-(NSArray*)grep:(BOOL(^)(id obj))block;
@end
#import "NSArray+grep.h"
@implementation NSArray (grep)
//[mixi iOSTraining 8.1 宿題](https://github.com/mixi-inc/iOSTraining/wiki/8.1-Blocks#宿題として)の解答
-(NSArray*)grep:(BOOL(^)(id obj))block{
NSMutableArray* mArray = [self mutableCopy];
NSMutableIndexSet *discards = [NSMutableIndexSet indexSet];
[self enumerateObjectsUsingBlock:^(id object,
NSUInteger idx,
BOOL *stop) {
if (!block(object)) {
[discards addIndex:idx];
}
}];
[mArray removeObjectsAtIndexes:discards];
NSArray *array = [mArray copy];
return array;
}
@end
//
// NSArrayGrepTest.m
//
#import <XCTest/XCTest.h>
#import "NSArray+grep.h"
@interface NSArrayGrepTest : XCTestCase
@end
@implementation NSArrayGrepTest
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testGrepClassName{
NSArray *before = @[ @"hoge", @"fuga", @"piyo", @1, @2, @3, @"foo", @"bar"];
NSArray *after = [before grep:^BOOL(id obj) {
return [obj isKindOfClass:[NSString class]];
}];
NSLog(@"%@", after); // @"hoge", @"fuga", @"piyo", @"foo", @"bar"
NSArray* expectationArray = @[@"hoge", @"fuga", @"piyo", @"foo", @"bar"];
[after enumerateObjectsUsingBlock:^(NSString* string,
NSUInteger index,
BOOL *stop){
XCTAssertEqualObjects(string, expectationArray[index]);
}];
}
- (void)testGrepClassName2{
NSArray *before = @[ @"hoge", @"fuga", @"piyo", @[@"www"], @"foo", @"bar"];
NSArray *after = [before grep:^BOOL(id obj) {
return [obj isKindOfClass:[NSString class]];
}];
NSLog(@"%@", after); // @"hoge", @"fuga", @"piyo", @"foo", @"bar"
NSArray* expectationArray = @[@"hoge", @"fuga", @"piyo", @"foo", @"bar"];
[after enumerateObjectsUsingBlock:^(NSString* string,
NSUInteger index,
BOOL *stop){
XCTAssertEqualObjects(string, expectationArray[index]);
}];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment