类簇在iOS开发中的应用

来源:互联网 发布:网络设计开发 编辑:程序博客网 时间:2024/05/16 17:24

转自:http://www.cocoachina.com/applenews/devnews/2014/0109/7681.html


类簇(class cluster)是一种设计模式,在Foundation Framework中被广泛使用,举个简单的例子
 
  1. NSArray *arr = [NSArray arrayWithObjects:@"foo",@"bar", nil]; 
  2. NSLog(@"arr class:%@", [arr class]); 
  3. // output: __NSArrayI 
 
显然__NSArrayI是一个私有类,来看看这个类的头文件
 
  1. @interface __NSArrayI : NSArray { 
  2.     unsigned int _used; 
  3.  
  4. //... 
 
可以看出__NSArrayI继承了NSArray。为什么要这么设计呢?拿NSNumber来举个例子,我们都知道NSNumber可以存储多种类型的数字,如Int/Float/Double等等,一种方式是把NSNumber作为基类,然后分别去实现各自的子类,像这样:
 
 
初看起来也没什么问题,但如果子类很多,像这样:
 
这对使用者来说显然不够方便,得记住这么多类。如果使用类簇,问题就变得简单了,把Number作为抽象基类,子类各自实现存取方式,然后在基类中定义多个初始化方式,像这样:
 
现在只需要记住一个类就可以了。NSNumber的初始化伪代码大概像这样:
 
  1. - (id)initWithBool 
  2.     return [[__NSCFBoolean alloc]init]; 
  3.  
  4. - (id)initWithLong 
  5.     return [[__NSCFNumber alloc]init]; 
  6.  
  7. //... 
 
在iOS项目中的应用
 
在开发app时经常会遇到表现和行为完全一样,但数据源不一样的情况。以花瓣app为例,同样是瀑布流,可能来自我喜欢的图片、某个画板下的图片、某个用户的图片等等。如果为每一种表现方式都新建一个Controller,并且使用这个Controller来初始化,那么就会遇到最开始提到的问题:子类太多,使用不便。这正好可以通过类簇来很方便地搞定。比如这样:
 
  1. @implementation HBWaterfallViewController 
  2. - (id)initWithLiked 
  3.     return [[HBLikedViewController alloc]init]; 
  4.   
  5. - (id)initWithBoardID:(NSInteger)boardID 
  6.     return [[HBBoardViewController alloc]initWithBoardID:boardID]; 
  7.   
  8. #pragma mark - 通用的方法 
  9.   
  10. - (PSUICollectionViewCell *)collectionView:(PSUICollectionView *)collectionView 
  11.                     cellForItemAtIndexPath:(NSIndexPath *)indexPath 
  12.     // ... 
  13.   
  14. // ... 
  15.   
  16. #pragma mark - 每个子类需要实现的方法 
  17.   
  18. - (void)fetchMoreData 
  19.     NSAssert(NO, @"子类需要实现此方法"); 
 
使用起来类似这样[[HBWaterfallViewController alloc]initWithBoardID:9527] 或 [[HBWaterfallViewController alloc]initWithLiked]。如果有新的DataSource,新加一个初始化方法即可,对于使用者来说,打开头文件,看下init开头的方法就行了。
 
再举个例子,现在很多应用需要同时兼顾iOS6和iOS7,在表现上需要为不同的系统加载不同的图片资源,最简单粗暴的方法就是各种if/else判断,像这样:
 
  1. if ([[UIDevice currentDevice]systemMajorVersion] < 7) 
  2.     /* iOS 6 and previous versions */ 
  3. else 
  4.     /* iOS 7 and above */ 
 
不够优雅,可以使用类簇的思想来去掉if/else判断,把跟视图具体元素无关的代码放在基类,跟系统版本相关的代码拆成两个子类,然后在各自的类中加载相应的资源。
  1. /* TestView.h */ 
  2. @interface TestView: UIView 
  3.  
  4. /* Common method */ 
  5. - ( void )test; 
  6.  
  7. @end 
  8.  
  9. /* TestView.m */ 
  10. @implementation TestView 
  11.  
  12. + (id)alloc 
  13.     if ([self class]== [TestView class]) 
  14.     { 
  15.         if ([[UIDevice currentDevice] systemMajorVersion] < 7) 
  16.         { 
  17.             return [TestViewIOS6 alloc]; 
  18.         } 
  19.         else 
  20.         { 
  21.             return [TestViewIOS7 alloc]; 
  22.         } 
  23.     } 
  24.     else 
  25.     { 
  26.         return [super alloc]; 
  27.     } 
  28.  
  29. - ( void )test 
  30. {} 
  31.  
  32. @end 
 
这里alloc时并没有返回TestView类,而是根据系统版本返回TestViewIOS6 或 TestViewIOS7。
 
  1. /* TestViewIOS6.m */ 
  2. @implementation TestViewIOS6: TestView 
  3.  
  4. - (void)drawRect: (CGRect)rect 
  5.     /* Custom iOS6 drawing code */ 
  6.  
  7. @end 
  8.  
  9. /* TestViewIOS7.m */ 
  10. @implementation TestViewIOS7 
  11.  
  12. - (void)drawRect: (CGRect)rect 
  13.     /* Custom iOS7 drawing code */ 
  14.  
  15. @end 
 
小结
类簇的本质其实是抽象工厂,类簇也可以有多个基类,如NSArray, NSMutableArray, 后者就是继承的前者。它对一些「大同小异」的问题,往往会有不错的效果。
 
来源:无网不剩

0 0
原创粉丝点击