QPChainable
为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" : @"俄罗斯"
})