Objective-C 筆記》使用 GCD 的 dispatch_apply 函數實現類似 Ruby 的 map 方法

Ruby 語言的 Array 類別有一個 map 方法,可以把一個 Block 應用到 Array 裡的每個元素上,並將 Block 的傳回值收集成一個新的 Array,例如:

a = ['a', 'b', 'c']
a.map {|e| e.upcase}   # => ['A', 'B', 'C']

在 Objective-C 裡可以利用 GCD 的 dispatch_apply 函數來實現 map 方法:

#import <Foundation/Foundation.h>

@interface NSArray (RAMethods)
- (NSArray *)map:(id (^)(id item))block;
@end
#import "NSArray+RAMethods.h"

@implementation NSArray (RAMethods)

- (NSArray *)map:(id (^)(id item))block {
    NSMutableArray *results = [NSMutableArray array];
    for (int i = 0; i < self.count; ++i) {
        [results addObject:[NSNull null]];
    }
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_apply(self.count, queue, ^(size_t index) {
        [results replaceObjectAtIndex:index withObject:block([self objectAtIndex:index])];
    });
    
    return results;
}
@end

使用方式:

#import "NSArray+RAMethods.h"
...

NSArray *array = @[@"a", @"b", @"c", @"d", @"e"];
NSArray *tmpArray = [array map:^(id item) {
                        NSLog(@"%@", item);
                        return [item uppercaseString];
                    }];
NSLog(@"----------");
NSLog(@"tmpArray: %@", tmpArray);

輸出的結果:

a
c
d
e
b
----------
tmpArray: (
    A,
    B,
    C,
    D,
    E
)

dispatch_apply 函數有三個參數:第一個參數是迭代次數,第二個參數是要使用的 Dispatch Queue ,第三個參數是要執行的 Block。

可以注意到在輸出結果中,虛線上方的字母次序跟 array 裡的次序不同,這是因為 dispatch_apply 函數會把第三個參數的 Block 加到 Dispatch Queue 裡,各個 Block 的執行時間不定,所以虛線上方的字母次序才會跟 array 裡的不同。