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

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

1

2

3

4

5

6

7

8

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 上。这里是地址

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

@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");

}

returnself;

}

}

- (ClassA *(^)(NSString *))bbb

{

return^(NSString *str)) {

//code

NSLog(@"%@", str);

returnself;

}

}

// 这里返回了ClassB的一个实例,于是后面就可以继续链式 ClassB 的 block 方法

// 见下面例子 .ccc(@"Objective-C").ddd(NO)

- (ClassB * (^)(NSString *))ccc

{

return^(NSString *str) {

//code

NSLog(@"%@", str);

ClassB* b = [[ClassB alloc] initWithString:ccc];

returnb;

}

}

//------------------------------------------

@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");

}

returnself;

}

}

// 最后我们可以这样做

id a = [ClassAnew];

a.aaa(YES).bbb(@"HelloWorld!").ccc(@"Objective-C").ddd(NO)