Block 链式调用

146 阅读2分钟

🔗 链式调用的本质

通过方法返回 Block,且 Block 的返回值是对象自身,实现连续的点语法调用:

person.run(@"跑步").eat(@"苹果").sleep();

🛠 实现步骤(以 Person 类为例)

1. 定义链式方法

// Person.h
@interface Person : NSObject

// 无参数方法
- (Person *(^)(void))run;
- (Person *(^)(void))eat;

// 带参数方法
- (Person *(^)(NSString *food))eatWithFood;
- (Person *(^)(NSInteger hours))sleep;

@end

2. 实现 Block 方法

// Person.m
@implementation Person

// 无参方法
- (Person *(^)(void))run {
    return ^{
        NSLog(@"开始跑步");
        return self; // 关键:返回对象自身
    };
}

// 带参数方法
- (Person *(^)(NSString *))eatWithFood {
    return ^(NSString *food) {
        NSLog(@"吃 %@", food);
        return self;
    };
}

// 链式终止方法(无返回值)
- (void (^)(void))sleep {
    return ^{
        NSLog(@"睡觉8小时");
    };
}

@end

🔍 调用示例

Person *person = [[Person alloc] init];

// 传统调用方式
[person run];
[person eatWithFood:@"苹果"];
[person sleep];

// 链式调用方式
person.run().eatWithFood(@"苹果").sleep();

// 混合参数调用
person.eatWithFood(@"香蕉").run().eatWithFood(@"苹果")();

⚙️ 实现原理

  1. 方法返回 Block

    • 方法签名格式:- (返回类型 (^)(参数类型))方法名
    • 例如:- (Person *(^)(NSString *))eatWithFood
  2. Block 内部逻辑

    • 执行具体操作(如打印日志、修改对象状态)
    • 返回 self 保证链式连续性(终止方法除外)
  3. ARC 内存管理

    • Block 捕获 self 时默认强引用
    • 需用 __weak 避免循环引用:
      __weak typeof(self) weakSelf = self;
      return ^{
          __strong typeof(weakSelf) strongSelf = weakSelf;
          [strongSelf doSomething];
          return strongSelf;
      };
      

📝 高级技巧

1. 支持多参数

- (Person *(^)(NSString *, NSInteger))action {
    return ^(NSString *name, NSInteger count) {
        NSLog(@"执行%@ %zd次", name, count);
        return self;
    };
}

// 调用
person.action(@"深蹲", 10);

2. 与建造者模式结合

Person.newBuilder
    .name(@"张三")
    .age(25)
    .address(@"北京")
    .build();

3. 链式终止设计

- (void)build {
    NSLog(@"对象构建完成");
}

// 调用
person.configA().configB().build();

🚧 注意事项

  1. 避免循环引用:在 Block 内使用 __weak 弱引用
  2. 方法命名规范:使用动词短语(如 withXxxenableXxx
  3. 调试技巧:用 NSLog(@"%@", [block class]) 查看 Block 类型
  4. 性能优化:频繁调用的 Block 建议缓存(static dispatch_once_t

🌰 完整示例(配置对象)

// Config.h
@interface Config : NSObject

- (Config *(^)(BOOL))enableLog;
- (Config *(^)(NSString *))setHost;

@end

// Config.m
@implementation Config {
    BOOL _enableLog;
    NSString *_host;
}

- (Config *(^)(BOOL))enableLog {
    return ^(BOOL enable) {
        _enableLog = enable;
        return self;
    };
}

- (Config *(^)(NSString *))setHost {
    return ^(NSString *host) {
        _host = [host copy];
        return self;
    };
}

@end

// 使用
Config.new.enableLog(YES).setHost(@"https://api.example.com");

参考 Masonry