分類彙整: iOS

Objective-C 筆記》GCC 的 C 擴充功能: Code Block Evaluation

在 NSHipster 看到 Clang 有支援 GCC 的擴充功能:Code Block Evaluation,看到後覺得真是驚為天人(又在亂用成語了XD),這個功能真是太實用了,立馬就在正在寫的專案裡用了這種寫法 😀

這個功能是用圓括弧()包起一個代碼區塊{},然後這個代碼區塊最後一個表達式的值就是返回的值,寫法就像這樣:

self.nameLabel = ({
    UILabel *label = [UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 44)];
    label.text = @"Riddle";
    label.textColor = [UIColor greenColor];
    label;
});

self.blogLabel = ({
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 50, 300, 40)];
    label.text = @"http://riddleapple.logdown.com";
    label.textColor = [UIColor redColor];
    label;
});

因為變數只能存活在宣告那個變數的大括號內,因此可以利用這個方式,重複使用一些通用的變數名稱而不會產生衝突!

Objective-C 筆記》NSSelectorFromString

在 Objective-C 裡,可以使用 NSSelectorFromString() 函式把一個 NSString 轉換成 Selector,這樣就可以在執行期才決定要傳送的訊息:

SEL aSelector = NSSelectorFromString(@"redColor");  // 把一個字串轉換成 Selector

例如,有一個儲存顏色字串的 Array :

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // color string array
        self.items = @[@"Red", @"Green", @"Blue", @"Yellow", @"Orange"];
    }
    return self;
}

然後在一個 TableView 裡顯示這些顏色字串與顏色:

#pragma mark - UITableView Data Source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }
    
    // 利用字串產生 Selector
    SEL colorMethod = NSSelectorFromString([NSString stringWithFormat:@"%@Color", [_items[indexPath.row] lowercaseString]]);

    if ([UIColor respondsToSelector:colorMethod]) {
        // 發送訊息
        cell.textLabel.textColor = [UIColor performSelector:colorMethod];
    }
    
    cell.textLabel.text = _items[indexPath.row];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

執行結果會像這樣:

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 裡的不同。

iOS 筆記》UIColor

每次使用 UIColor 的 +colorWithRed:green:blue:alpha: 方法都要把 RGB 數值換算成 0 ~ 1.0 間的浮點數,覺得太麻煩了,可以使用下面這個方法,給一組 RGB 十進制數值的陣列:

#import <UIKit/UIKit.h>

@interface UIColor (RAMethods)
+ (UIColor *)colorWithRGB:(NSArray *)array alpha:(CGFloat)alpha;
@end
#import "UIColor+RAMethods.h"

@implementation UIColor (RAMethods)

+ (UIColor *)colorWithRGB:(NSArray *)array alpha:(CGFloat)alpha {
    if (array.count != 3) {
        return nil;
    }
    
    NSMutableArray *results = [NSMutableArray array];
    
    for (NSNumber *number in array) {
        float colorValue = ((float)[number intValue])/255;
        [results addObject:[NSNumber numberWithFloat:colorValue]];
    }

    return [self colorWithRed:[results[0] floatValue]
                        green:[results[1] floatValue]
                         blue:[results[2] floatValue]
                        alpha:alpha];
}
@end

使用方式:

#import "UIColor+RAMethods.h"

...

// R: 127, G: 127, B: 127 (灰色)
UIColor *color = [UIColor colorWithRGB:@[@127, @127, @127] alpha:1.0f];

// R:255, G: 0, B: 0 (紅色)
UIColor *color = [UIColor colorWithRGB:@[@255, @0, @0] alpha:1.0f];