在当前项目的一些内容加工逻辑较多的界面,我会使用ViewModel
来对Model
进行一层包装,这样可以保持Model
的纯净,也可以减少Controller
中弱逻辑代码的堆叠。当然,部分公用内容也是可以通过给Model
添加分类来实现的,ViewModel
更多是提供特定页面的定制化内容。
由于项目并没有采用MVVM
模式,也就没有引入ReactiveCocoa
,所以项目里面比较多这样的代码:
1 | NSArray <TBVEmployee *> *employees = @[[TBVEmployee new]]; |
这段代码主要是为了将Model
转化成ViewModel
。
这里可以给NSArray
增加一个tbv_map
方法,让这段代码阅读起来更加函数式:
1 | @interface NSArray (SwiftOperation) |
添加分类后,上面那段代码可以这样写:
1 | NSArray *employees = @[[TBVEmployee new]]; |
嗯!看起来清爽了不少。但是写多了之后会有一个小瑕疵:为了能map
到NSArray
可容纳的所有类型,block
的传参使用了id
类型,当需要使用形参的个别属性时,我需要手动更改id
为具体的类名:
1 | NSMutableArray *items = [employees tbv_map:^id(TBVEmployee *value) { |
有没有什么法子,能让Xcode
的智能提示帮我直接预测到想要map
的元素类型呢?
答案是Objective-C
的范型。虽然Objective-C
对于范型的支持还是比较弱的,但是处理当前的这个需求还是可以的。
先给NSArray
分类添加范型:
1 | @interface NSArray <T> (SwiftOperation) |
然后在使用时,指定需要map
数组的元素类型:
1 | NSArray <TBVEmployee *> *employees = @[[TBVEmployee new]]; |
然后Xcode
就会根据数组元素的类型,做出智能提示啦:
以此还可以增加其它的操作:
1 | @interface NSArray <T> (SwiftOperation) |
这里只添加了NSArray
类型的操作,NSDictionary
、NSSet
这类集合类型也可以以此类推来实现。不过上面的方法只是做了一层简易的包装,并没有延迟计算啥的,只是让我写起来能更加开心、舒畅点吧。
更改
2017-07-06 :
需要注意的是 instancetype
会包含范型检查,为了避免使用者过多地进行强制类型转换, tbv_map
可以修改成如下形式:
1 | - (NSArray *)tbv_map:(id (^)(T value))block; |