QPChainable 1.2.0

QPChainable 1.2.0

Qiongpan Ke 维护。



  • keqiongpan

QPChainable

GitHub License CocoaPods Version Carthage Compatible CocoaPods Platforms

为Objective-C提供便捷的方法构造支持链式表达式的功能。

使用CocoaPods集成

QPChainable 支持使用第三方库管理工具 CocoaPods 集成到您的 Xcode 工程。详细信息请参阅 此处

您可以在 Podfile 文件中添加以下项:

pod 'QPChainable', '~> 1.0'

使用Carthage集成

QPChainable 同时兼容使用去中心化的库管理工具 Carthage 集成到您的 Xcode 工程。

您可以在 Cartfile 文件中添加以下项:

github "keqiongpan/QPChainable" ~> 1.0

使用说明

1. 声明链式表达式函数

要为某个类添加支持链式表达式的函数,可以在该类的声明体内使用 QP_CHAINABLE_DECLARE 宏函数声明该函数。

使用方法:

QP_CHAINABLE_DECLARE(<函数名>, <参数列表>[, <返回值类型>]);

其中 <参数列表> 需要使用圆括号 () 括起来; <返回值类型> 是可选项,默认为 instancetype

使用示例:

@interface QPPacketMaker : NSObject

- QP_CHAINABLE_DECLARE(length, (void), NSUInteger);
- QP_CHAINABLE_DECLARE(append, (QPMultipartData *data), QPPacketMaker *);
- QP_CHAINABLE_DECLARE(send, (void), QPPacketMaker *);

@end

2. 实现链式表达式函数

当定义了类支持的链式表达式函数,可以在该类的实现中使用 QP_CHAINABE_IMPLEMENTATION 宏定义函数的实现逻辑。

使用方法:

QP_CHAINABLE_IMPLEMENTATION(<函数名>, <参数列表>[, <返回值类型>], <函数体>);

其中 <参数列表> 需要用圆括号 () 包围;<返回值类型> 为可选项,默认值为 instancetype;<函数体> 需要用花括号 {} 包围。

使用示例:

@implementation QPPacketMaker

#pragma mark length()
- QP_CHAINABLE_IMPLEMENTATION(length, (void), NSUInteger, ({
    return self.data.length;
}))

@end

3. 支持继承混用的链式表达式函数

默认情况下,父类和子类分别实现的链式表达式函数是不能混合使用的,因为这些函数的返回值类型不一致,父类的链式表达式函数通常返回父类实例对象类型,无法通过点语法“.”调用子类的链式表达式函数。

要实现父类和子类实现的链式表达式函数的交叉混合使用,可以将父类和子类都改为泛型类,并且将最终使用的实例对象类型通过泛型参数传递给父类和子类,使得两者都使用该类型作为链式表达式函数的返回值类型。另外还需要实现一个装饰类,用于向调用者提供最终使用的对象。

装饰类的声明与实现,可以使用以下这对宏:

QP_CHAINABLE_DECORATOR_DECLARE(<装饰类>, <具体类>);
QP_CHAINABLE_DECORATOR_IMPLEMENTATION(<装饰类>, <具体类>);

其中 <具体类><装饰类> 的父类,是带一个实例类型参数的泛型类,而 <装饰类> 是普通类,没有泛型参数。

宏展开时会为 <具体类> 添加一个 - (<装饰类> *)make 的方法,使得无论当前对象的类型是装饰类还是其父类的实例对象类型,都可以通过调用 make 来开始链式表达式。

使用示例:

@interface QPConcretePacketMaker<instancetype> : NSObject

- QP_CHAINABLE_DECLARE(length, (void), NSUInteger);
- QP_CHAINABLE_DECLARE(append, (QPMultipartData *data));
- QP_CHAINABLE_DECLARE(send, (void));

@end

@interface QPConcreteVideoPacketMaker<instancetype> : QPConcretePacketMaker<instancetype>

- QP_CHAINABLE_DECLARE(subtitle, (QPSubtitleData *data));

@end

QP_CHAINABLE_DECORATOR_DECLARE(QPVideoPacketMaker, QPConcreteVideoPacketMaker);

//
// 调用示例:
// QPVideoPacketMaker *maker = [[QPVideoPacketMaker alloc] init];
// maker.append(videoData).subtitle(subtitleData).send();
//

4. 支持数组字面量的链式表达式函数

如果一个链式表达式函数需要传入一个数组对象(NSArray *),可以有多种传入方法,如数组对象或数组字面量(@[<对象1>, ...])等。但这些方法都不够优雅,因为数组对象需要提前拼装好数组内容,数组字面量在换行对齐时,前面可能会留下很大的空白。

现在,可以使用以下函数宏来定义链式表达式函数,从而提供更优雅的方法传入数组字面量:

QPChainableArray(<对象类型>, {<对象1>, ...})

使用示例:

#define members(...) \
        membersFromArray(QPChainableArray(NSString *, __VA_ARGS__))
- QP_CHAINABLE_DECLARE(members, (void *_FOR_CODE_HINT_ONLY_));
- QP_CHAINABLE_DECLARE(membersFromArray, (NSArray<NSString *> *));

unsc.permanent.members({
    @"中国",
    @"美国",
    @"英国",
    @"法国",
    @"俄罗斯"
})

5. 支持字典字面量的链式表达式函数

如果一个链式表达式函数需要传入一个字典对象(NSDictionary *),同样可以有多种传入方法,如字典对象或字典字面量(@{<键1>:<值1>, ...])等。但这些方法都不够优雅,因为字典对象需要提前拼装好字典内容,字典字面量在换行对齐时,前面可能会留下很大的空白。

现在,可以使用以下函数宏来定义链式表达式函数,从而提供更优雅的方法传入字典字面量:

QPChainableDictionary(<键类型>, <值类型>, {<键1>:<值1>, ...})

使用示例:

#define members(...) \
        membersFromDictionary(QPChainableDictionary(NSString *, NSString *, __VA_ARGS__))
- QP_CHAINABLE_DECLARE(members, (void *_FOR_CODE_HINT_ONLY_));
- QP_CHAINABLE_DECLARE(membersFromDictionary, (NSDictionary<NSString *, NSString *> *));

unsc.permanent.members({
    @"CN" : @"中国",
    @"US" : @"美国",
    @"UK" : @"英国",
    @"FR" : @"法国",
    @"RU" : @"俄罗斯"
})