类簇在iOS开发中的应用
2016-02-15 15:31
579 查看
类簇(class cluster)是一种设计模式,在Foundation Framework中被广泛使用,举个简单的例子
显然
可以看出
初看起来也没什么问题,但如果子类很多,像这样:
这对使用者来说显然不够方便,得记住这么多类。如果使用类簇,问题就变得简单了,把Number作为抽象基类,子类各自实现存取方式,然后在基类中定义多个初始化方式,像这样:
现在只需要记住一个类就可以了。
在开发app时经常会遇到表现和行为完全一样,但数据源不一样的情况。以花瓣app为例,同样是瀑布流,可能来自我喜欢的图片、某个画板下的图片、某个用户的图片等等。如果为每一种表现方式都新建一个Controller,并且使用这个Controller来初始化,那么就会遇到最开始提到的问题:子类太多,使用不便。这正好可以通过类簇来很方便地搞定。比如这样:
使用起来类似这样
再举个例子,现在很多应用需要同时兼顾iOS6和iOS7,在表现上需要为不同的系统加载不同的图片资源,最简单粗暴的方法就是各种if/else判断,像这样:
不够优雅,可以使用类簇的思想来去掉if/else判断,把跟视图具体元素无关的代码放在基类,跟系统版本相关的代码拆成两个子类,然后在各自的类中加载相应的资源。
这里
类簇的本质其实是抽象工厂,类簇也可以有多个基类,如
后者就是继承的前者。它对一些「大同小异」的问题,往往会有不错的效果。
Cocoa Core Competencies
Strategies to support iOS7 UI
Class Cluster Concepts in Objective-C
--EOF--
NSArray *arr = [NSArray arrayWithObjects:@"foo",@"bar", nil]; NSLog(@"arr class:%@", [arr class]); // output: __NSArrayI
显然
__NSArrayI是一个私有类,来看看这个类的头文件
@interface __NSArrayI : NSArray { unsigned int _used; } //...
可以看出
__NSArrayI继承了
NSArray。为什么要这么设计呢?拿NSNumber来举个例子,我们都知道NSNumber可以存储多种类型的数字,如Int/Float/Double等等,一种方式是把NSNumber作为基类,然后分别去实现各自的子类,像这样:
初看起来也没什么问题,但如果子类很多,像这样:
这对使用者来说显然不够方便,得记住这么多类。如果使用类簇,问题就变得简单了,把Number作为抽象基类,子类各自实现存取方式,然后在基类中定义多个初始化方式,像这样:
现在只需要记住一个类就可以了。
NSNumber的初始化伪代码大概像这样:
- (id)initWithBool { return [[__NSCFBoolean alloc]init]; } - (id)initWithLong { return [[__NSCFNumber alloc]init]; } //...
在iOS项目中的应用
在开发app时经常会遇到表现和行为完全一样,但数据源不一样的情况。以花瓣app为例,同样是瀑布流,可能来自我喜欢的图片、某个画板下的图片、某个用户的图片等等。如果为每一种表现方式都新建一个Controller,并且使用这个Controller来初始化,那么就会遇到最开始提到的问题:子类太多,使用不便。这正好可以通过类簇来很方便地搞定。比如这样:@implementation HBWaterfallViewController - (id)initWithLiked { return [[HBLikedViewController alloc]init]; } - (id)initWithBoardID:(NSInteger)boardID { return [[HBBoardViewController alloc]initWithBoardID:boardID]; } #pragma mark - 通用的方法 - (PSUICollectionViewCell *)collectionView:(PSUICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { // ... } // ... #pragma mark - 每个子类需要实现的方法 - (void)fetchMoreData { NSAssert(NO, @"子类需要实现此方法"); }
使用起来类似这样
[[HBWaterfallViewController alloc]initWithBoardID:9527]或
[[HBWaterfallViewController alloc]initWithLiked]。如果有新的DataSource,新加一个初始化方法即可,对于使用者来说,打开头文件,看下init开头的方法就行了。
再举个例子,现在很多应用需要同时兼顾iOS6和iOS7,在表现上需要为不同的系统加载不同的图片资源,最简单粗暴的方法就是各种if/else判断,像这样:
if ([[UIDevice currentDevice]systemMajorVersion] < 7) { /* iOS 6 and previous versions */ } else { /* iOS 7 and above */ }
不够优雅,可以使用类簇的思想来去掉if/else判断,把跟视图具体元素无关的代码放在基类,跟系统版本相关的代码拆成两个子类,然后在各自的类中加载相应的资源。
/* TestView.h */ @interface TestView: UIView /* Common method */ - ( void )test; @end /* TestView.m */ @implementation TestView + (id)alloc { if ([self class]== [TestView class]) { if ([[UIDevice currentDevice] systemMajorVersion] < 7) { return [TestViewIOS6 alloc]; } else { return [TestViewIOS7 alloc]; } } else { return [super alloc]; } } - ( void )test {} @end
这里
alloc时并没有返回
TestView类,而是根据系统版本返回
TestViewIOS6或
TestViewIOS7。
/* TestViewIOS6.m */ @implementation TestViewIOS6: TestView - (void)drawRect: (CGRect)rect { /* Custom iOS6 drawing code */ } @end /* TestViewIOS7.m */ @implementation TestViewIOS7 - (void)drawRect: (CGRect)rect { /* Custom iOS7 drawing code */ } @end
小结
类簇的本质其实是抽象工厂,类簇也可以有多个基类,如NSArray,
NSMutableArray,
后者就是继承的前者。它对一些「大同小异」的问题,往往会有不错的效果。
参考
Cocoa Core CompetenciesStrategies to support iOS7 UI
Class Cluster Concepts in Objective-C
--EOF--
相关文章推荐
- iOS开发- 获取精确剩余电量
- IOS 开发 证书显示 此证书签发者无效 解决办法
- 打包生成IPA包时遇到错误:missing ios distribution signing identity for XXXXXXXXXX
- 关于IOS开发证书显示“此证书的签发者无效”解决方法
- iOS可执行文件瘦身方法
- 2016苹果开发者证书无效,怎么办
- iOS8以iOS8以下的系统present一个半透明的ViewController的方法
- iOS 整型转换警告"NSInteger' should not be used as format arguments; add an explicit cast to 'long' inste"
- ios开发证书变成证 “此证书的签发者无效了”
- iOS 7中自动布局教程
- iOS-关闭应用时想让应用直接退出的方法
- IOS开发证书显示“此证书的签发者无效”解决方法
- IOS开发证书显示“此证书的签发者无效”解决方法
- IOS开发证书变成“此证书的签发者无效”解决方法
- iOS 设置label的边距
- ios-此证书的签发者无效
- iOS开发证书变成“此证书的签发者无效”解决方法
- iOS IM开发准备工作(二)protobuf-objc安装及使用
- iOS中Block总结
- IOS开发证书变成“此证书的签发者无效”解决方法