【发烂渣】iOS中Objective-C的无限点链式语法

1,772 阅读3分钟

Objective-C语法

在Objective-C的语法中,是在众多语言中更加接近自然语言的,代码的可读性较高的。可是事情的都是双面性的。因为他使用的不是一般的开发语言的点链式语法,而是是使用了中括号链式语法。这就到导致了十分啰嗦和很长。

OC的中括号语法:
[[[object aFunc] bFunc] cFunc:@"String"]

点链式语法
object.aFunc(1).bFunc(1).cFunc("string")

Objective-C的链式语法介绍

OC中语法大致分为3种类型。

  1. 点语法【.】:一般用于属性的获取和设置。
  2. 中括号【[]】:一般用于方法的调用。
  3. 括号【()】 : 一般是block的调用。

无限点链式实现原理

从OC的语法中可以知道,要实现点链式语法,这就必须要借助于Block。

Block是一个匿名函数或者是一个函数指针,他可以携带参数同时也可以拥有返回值。

所以只要把Block的返回值都设置为当前类的的实例本身,这样就可以实现无限的调用了。

object.func1().func2(1).func(@"string")

实现的方式有两种:

  1. 定义只读的Block类型的属性,并把返回值类型设为当前类本身,然后实现这些 Block 属性的 getter 方法。
  2. 定义方法,然后通过方法的调用。

下面直接上代码:

DFPeople.h

//
//  DFPeople.h
//  ChainProgramming
//
//  Created by raymond on 2021/3/24.
//
#import <Foundation/Foundation.h>

@interface DFPeople : NSObject

//第一种方法
//定义只读的Block类型的属性,并把返回值类型设为当前类本身,然后实现这些 Block 属性的 getter 方法。
@property (readonly, nonatomic, copy) DFPeople * (^salary)(NSInteger salary);

//第二种方法
//定义方法,然后通过方法的调用。
-(DFPeople* (^)(NSString *))myName;

@end

DFPeople.m

//
//  DFPeople.m
//  ChainProgramming
//
//  Created by raymond on 2021/3/24.
//

#import "DFPeople.h"

@interface DFPeople()

@property (nonatomic, assign) NSInteger _salary;

@property (nonatomic, copy) NSString *name;
@end

@implementation DFPeople

-(instancetype) init{
    self = [super init];
    if(self){
    }
    return self;
}

-(DFPeople* (^)(NSString *))myName{
    
    return ^id(NSString *name){
        self.name = name;
        NSLog(@"my name is %@",(self.name));
        return self;
    };
}

-(DFPeople * (^)(NSInteger salary))salary{
    
    return ^id(NSInteger salary){
        self._salary += salary;
        NSLog(@"my salary is %@",(self._salary));
        return self;
    };
}
@end

调用:

//
//  ViewController.m
//  ChainProgramming
//
//  Created by raymond on 2021/3/24.
//

#import "ViewController.h"
#import "DFPeople.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    DFPeople *people = [DFPeople new];
    people.myName(@"Raymond").salary(1000);
    
}
@end

分析

DFPeople.h
// 在DFPeople.h头文件中,声明了一个copy属性的block变量。
// 设为readonly是为了限制只实现 getter 方法,同时防止被外部修改。
// 这里Block属性携带一个 NSInteger类型的参数,命名为salary(),而其返回值类型为当前 DFPeople,就是当前的类
@property (readonly, nonatomic, copy) DFPeople * (^salary)(NSInteger salary);

DFPeople.m
// 在DFPeople.m头文件中,实现.h文件中Block的getter的方法
// 而对于返回的 Block,其返回值类型为 DFPeople,所以在该 Block 里返回了 self。
-(DFPeople * (^)(NSInteger salary))salary{
    
    return ^id(NSInteger salary){
        self._salary += salary;
        NSLog(@"my salary is %@",(self._salary));
        return self;
    };
}

所以在调用的时候 [DFPeople new].salary(1000),其实就是调用了[[DFPeople new] salary].然后返回一个 Block。如下:
return ^id(NSInteger salary){
        self._salary += salary;
        NSLog(@"my salary is %@",(self._salary));
        return self;
    };
    
这样当调用该 Block 时,会返回 self(即类实例本身),流程如下:

(1) DFPeople.salary -> 获得一个 Block;

(2) DFPeople.salary(1000) -> Block 的执行,并返回了 self(即实例 calc)

(3) 于是在 DFPeople.salary(1000) 后面可继续访问 DFPeople 的其他属性,实现无限点链。 

一点点小的看法

在对于这种点链式语法的实现中,我更倾向于通过定义block的变量。因为这种在使用的时候,Xcode会给到代码提示。而如果使用方法定义模式,则不会有代码提示。如图:

定义block的变量

Screen Shot 2021-03-26 at 01.49.46.png

方法定义模式

Screen Shot 2021-03-26 at 01.49.30.png

完毕

这里就介绍完了OC实现点链式语法。如果能帮到你的话,麻烦点赞一下。谢谢

最后祝各位,代码永远没Bug,生活愉快~~~