如何在Objective-C中实现链式语法?

版权所有,禁止匿名转载;禁止商业使用。


在接触到开源项目 Masonry 后,里面的布局约束的链式写法让我颇感兴趣,就像下面这样


UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[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);
}];

其他语言比如 Lua, 实现链式语法很容易。但在 Objective-C 中,如何实现链式语法呢?


注:这里讨论的链式语法特指的是 点链式语法 ,不同于 中括号链式语法 ,如 [[[[someObj method1] method2] method3] method4:someParam] 。中括号链式语法相对而言更简单些,每个方法的返回值是下一个方法的发送者即可。


查看 Masonry 源码,起初没看明白,于是搜索了下 Stackoverflow,没有发现类似的问题,便将这个问题发布在了 Stackoverflow 上。 这里是地址。


总结了下,贴下代码,做个说明。


@class ClassB;
@interface ClassA : NSObject
// 1. 定义一些 block 属性
@property(nonatomic, readonly) ClassA *(^aaa)(BOOL enable);
@property(nonatomic, readonly) ClassA *(^bbb)(NSString* str);
@property(nonatomic, readonly) ClassB *(^ccc)(NSString* str);
@implement ClassA
// 2. 实现这些 block 方法,block 返回值类型很关键,影响着下一个链式
- (ClassA *(^)(BOOL))aaa
{
  return ^(BOOL enable) {
    //code
    if (enable) {
      NSLog(@"ClassA yes");
    } else {
      NSLog(@"ClassA no");
    }
    return self;
  }
}
- (ClassA *(^)(NSString *))bbb
{
  return ^(NSString *str)) {
    //code
    NSLog(@"%@", str);
    return self;
  }
}
// 这里返回了ClassB的一个实例,于是后面就可以继续链式 ClassB 的 block 方法
// 见下面例子 .ccc(@"Objective-C").ddd(NO)
- (ClassB * (^)(NSString *))ccc
{
  return ^(NSString *str) {
    //code
    NSLog(@"%@", str);
    ClassB* b = [[ClassB alloc] initWithString:ccc];
    return b;
  }
}
//------------------------------------------
@interface ClassB : NSObject
@property(nonatomic, readonly) ClassB *(^ddd)(BOOL enable);
- (id)initWithString:(NSString *)str;
@implement ClassB
- (ClassB *(^)(BOOL))ddd
{
  return ^(BOOL enable) {
    //code
    if (enable) {
      NSLog(@"ClassB yes");
    } else {
      NSLog(@"ClassB no");
    }
    return self;
  }
}
// 最后我们可以这样做
id a = [ClassA new];
a.aaa(YES).bbb(@"HelloWorld!").ccc(@"Objective-C").ddd(NO)


0 0