相信用过 kotlin 的拓展方法的小伙伴, 没有太爽的, 比如
String("123").also{
// print
}.also {
// store
}.also {
// something else
}
这才是现代编程语法嘛, 能用一句话写完就别分两句写
可是项目还在用 objective-c , 那么今天我们就来拓展一下, 实现下面的效果
@"123".also(^(NSString *it){
// print
}).also(^(NSString *it){
// store
}).also(^(NSString *it){
// something else
})
虽然还达不到上面的简洁, 但起码效果一样
这里的 it 就是代表 "123" 这个字符串, "123" 也可以是其它对象, 比如NSData, NSDictionary等等
直接上代码
typedef void (^StringAlso)(NSString * _Nullable);
@interface NSString (ALSO)
- (NSString *(^)(StringAlso))also;
@end
@implementation NSString (ALSO)
- (NSString *(^)(StringAlso))also {
return ^(StringAlso block) {
block(self);
return self;
};
}
@end
解释一下
- StringAlso定义的一个可以接收字符串本身的 block
- @interface NSString (ALSO)定义NSString的拓展类
- 这里的also方法返回是 function(StringAlso block), 所以才能使用@"123".also(^)这种dot语法, 而不需要[@"123" also(^)]
- 如果定义function also(StringAlso block)加了参数的话, 对象就不能直接使用dot 语法了.
- 因为 oc 没有泛型, 如果想直接拓展NSObject对所有对象生效, also(^(NSString *it)这里会报错, 而且also.also后面都变成了NSObject, 链式就断了.
参考了Objective-C 实现链式调用, 文章了实现了自定义对象(MyObject)的链式调用, 本文就是在这个基础上实现了系统自带的对象(NSData/NSString)的链式调用, 系统自带的拓展使用频率更高, 感兴趣的朋友可以去看看
有个缺点是如果需要拓展NSData, NSDcitionary的话, 需要分别定义, 比如NSData
typedef void (^DataAlso)(NSData * _Nullable);
@interface NSData (ALSO)
- (NSData *(^)(DataAlso))also;
@end
@implementation NSData (ALSO)
- (NSData *(^)(DataAlso))also {
return ^(DataAlso block) {
block(self);
return self;
};
}
@end
所幸常用的对象并不多, 分开定义也能接受
按照这种写法, Kotlin 其它操作符let, with, run都能搬过来用用.
再在xcode中增加一个snippet, 输入also自动补齐代码, 效果如下:
来添加这个效果, 首先先在xcode中输入以下代码
其中的<#type#>会被自动替换, 右键高亮部分, 选择Create Code Snippet
稍微修改下圈的部分
好用了不少😄