[iOS][OC] 四個(gè) block 小技巧

一、 一行代碼執(zhí)行 block 的安全調(diào)用

基于 判斷對(duì)象是否為 nil 的處理,obj ?: someDefault 的思路,調(diào)整 block 的調(diào)用

void(^block)(void) = ...;
!block ?: block(); // 安全調(diào)用

PS: 如果是 Swift 的可選類型閉包,則可利用可選鏈處理

var closure: (() -> Void)? = ...
closure?()  // 可選鏈調(diào)用

二、利用系統(tǒng)現(xiàn)成的 typedef 的相關(guān) block

比如 GCD 中關(guān)于無參數(shù)無返回值的 typedef

typedef void (^dispatch_block_t)(void);

這樣就可以很愉快地利用 dispatch_block_t 來聲明無參數(shù)和無返回值的 block 了,而在 UIKit 中有很多 block 參數(shù)都是無參數(shù)無返回值類型 block,在實(shí)際業(yè)務(wù)中也可以利用,比如 上一篇文章中末尾的應(yīng)用 注意自定義 AlertController 的回調(diào)時(shí)機(jī)。

Swift 中的此用法暫時(shí)沒有找到很合適的,可以從一個(gè)協(xié)議中看到類似的定義

DispatchSourceProtocol.DispatchSourceHandler
extension DispatchSourceProtocol {

    public typealias DispatchSourceHandler = @convention(block) () -> Swift.Void
....
}1

更多的,繼續(xù)挖掘?qū)W習(xí)。

三、使用 block 作為函數(shù)/方法多個(gè)返回值的方案

在 OC 中一個(gè)方法返回多個(gè)參數(shù)有一些方案,比如使用指針的指針(類似返回 NSError 的用法),或者聲明字典、模型或者自定義一個(gè) 元組Tuple 類等。再者,就是使用 block 了,通過傳遞 block 將返回值取出的方式,舉例如下:


typedef NSInteger Int;

- (void)doSomeCalculate {
    Int a = 1;
    Int b = 2;
    __block Int sumR =  0;
    __block Int minR = 0;
    __block Int maxR = 0;
    
    [self calculateA:a b:b result:^(Int sum, Int min, Int max) {
        sumR = sum;
        minR = min;
        maxR = maxR;
    }];
    
    NSLog(@"sum %zd min %zd max %zd", sumR, minR, maxR);
}

- (void)calculateA:(NSInteger)a
                 b:(NSInteger)b
            result:(void(^)(Int sum, Int min, Int max))resultBlock {
    if (!resultBlock) return;
    
    resultBlock(a + b, MIN(a, b), MAX(a, b));
    
    return [self doNothingButPrint];
}

存在使用了類的成員變量而導(dǎo)致循環(huán)引用的情況,需要使用 weak- strong-dance,并在訪問實(shí)例變量使用結(jié)構(gòu)體訪問成員的操作符 ->

@interface SomeClass : NSObject

@property (nonatomic, copy) dispatch_block_t block;

@end

typedef NSInteger Int;

@implementation SomeClass
{
    Int _sum;
}


- (void)changeIvar {
    __weak typeof(self) weakSelf = self;
    self.block = ^{
        __strong typeof(SomeClass *) strongSelf = weakSelf;
        if (!strongSelf) return;
        strongSelf->_sum = 1024;
    };
}

@end

四、使用返回 對(duì)象本身的 block 實(shí)現(xiàn)鏈?zhǔn)秸Z法

經(jīng)典的例子是 OC 的自動(dòng)布局第三方框架 Masonry 的使用,

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
    make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
    make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];

其內(nèi)部實(shí)現(xiàn)的主要思路是兩個(gè)

  • 聲明一個(gè)只讀 block 屬性供外部調(diào)用,此 block 屬性返回實(shí)例本身
  • 聲明一個(gè)屬性,調(diào)用后返回一個(gè)實(shí)例(可以是本身),并可以執(zhí)行額外操作
- (MASConstraint * (^)(CGFloat))offset {
    return ^id(CGFloat offset){
        self.offset = offset;
        return self;
    };
}

不難看出,在一定程度上說,方法都可以轉(zhuǎn)換成 block 的形式調(diào)用,而 block 連續(xù)返回實(shí)例本身,從而可以實(shí)現(xiàn)鏈?zhǔn)秸Z法調(diào)用,提高代碼的可讀性,嘗試實(shí)現(xiàn)一個(gè)鏈?zhǔn)郊臃ㄕ{(diào)用如下:

@interface Dot : NSObject

@property (nonatomic, readonly) Dot *then;
@property (nonatomic, readonly) Dot *(^add)(NSInteger a);

- (NSInteger)getCurrent;

@end

@interface Dot ()
{
    NSInteger _current;
}

@end

@implementation Dot

- (NSInteger)getCurrent {
    return _current;
}

- (Dot *)then { return self; };

- (Dot *(^)(NSInteger))add {
    return ^Dot *(NSInteger a){
        _current += a;
        return self;
    };
}

- (void)dealloc {
    NSLog(@"dot dealloc %@", self);
}

@end

/// 調(diào)用
        Dot *dot = [[Dot alloc] init];
        dot.add(1).then.add(2).then.add(3);
        NSLog(@"now -> %zd", [dot getCurrent]); // 打印出 6
        dot = nil;

使用鏈?zhǔn)秸Z法有一個(gè)很大的前提是調(diào)用 block 前該 block 不能為空,所以使用時(shí)注意挑選調(diào)用者不為空的場(chǎng)景,參考 Masonry
再者,鏈?zhǔn)秸Z法在構(gòu)造構(gòu)造時(shí)有很好的優(yōu)勢(shì),比如純代碼構(gòu)造 UI 控件,推薦閱讀以下 LinkBlock, 從而這樣寫一個(gè) Label

UILabelNew
.labText(@"UILable").labNumberOfLines(0).labAlignment(NSTextAlignmentCenter)
.viewSetFrame(20,200,150,80)
.viewBGColor(@"#CCCCCC".strToUIColorFromHex())
.viewAddToView(self.view);

此外,block 在很多開源項(xiàng)目中都有很好的實(shí)踐,推薦:

誠邀你來討論我的專題, QQ群 287698622

加我微信溝通。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容