sdk接口设计

SDK的设计一般是由SDK所提供的服务决定的。如果SDK只是给数据提供接口,那除了必要的层次设计、合理的设计模式外,SDKManager对外要简洁易用,返回类型清晰,另外尽可能的使不同端的接口一致。

如果SDK所提供的接口是异步返回的,通常情况下,需要在调用的时候传入一个Block。在SDK内部完成异步任务后,调用block返回数据。

对于这种情况,我们会给接口定义相应的Block,在Block的参数中,指定具体的参数类型,这样,调用者就可以比较清晰的得知该接口返回的数据模型。

如下,返回值是一个字典:

1
2
3
4
5
6
7
8
9
// 定义
typedef void(^Response)(NSDictionary *dictionary);

- (void)goblock:(Response)response;

// 调用
[p goblock:^(NSDictionary *dictionary) {
// do something
}];

如上,当接口数量较多,且返回的具体类型不同时,就需要定义大量的Block应对。或者,使用id类型。让调用者在数据返回时,自行查看返回的具体类型。

1
2
3
4
5
6
7
8
9
// 定义
typedef void(^Response)(id obj);

- (void)goblock:(Response)response;

// 调用
[p goblock:^(id obj) {
// do something
}];

两种方式都有缺点,那有没有一种方式,既可以省去定义大量block又可以在调用者调用接口时即可知道返回的数据具体类型呢?

答案是:有的。

在iOS中,有一个objectType类型,该类型允许在一个类声明时再指定具体的类型,同时,此类形式的泛型也可用关键词covariantcontravariant指定协变(子类型转父类型)或逆变(父类型转子类型)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 定义
@interface TAFResponse<objectType> : NSObject
@property (nonatomic, strong) objectType what;
@end

// 在接口中的声明方式
- (void)run:(void(^)(TAFResponse<NSString *> *response))callback;


// 实现
- (void)run:(void(^)(TAFResponse<NSString *> *response))callback {
TAFResponse *rsp = [[TAFResponse alloc] init];
rsp.what = @"test";
if (callback) {
callback(rsp);
}
}

// 调用
[p run:^(TAFResponse<NSString *> * _Nonnull response) {
NSLog(@"%@", response.what);
}];