关于iOS开发:iOS开发-简化view-controller

28次阅读

共计 3620 个字符,预计需要花费 10 分钟才能阅读完成。

导语

view controller 通常是一个我的项目中最宏大的文件,因为它外面常常蕴含了不属于它的代码,同时这也使它成为代码中最难以重用的局部。所以为 view controller 瘦身,让其中的代码复用性更强,把相干代码放到正确的中央显得尤其重要。

iOS 开发交换技术群:563513413,不论你是大牛还是小白都欢送入驻,分享 BAT, 阿里面试题、面试教训,探讨技术,大家一起交流学习成长!

将 Data Source 和其余协定拆散

为 view controller 瘦身最无效的办法就是把 UITableViewDataSource 中的代码移动到相干的类中,具体的办法能够参阅《iOS 利用开发 扼要 TableView》中的相干实现。

而更进一步,不只是 TableView,这个办法能够扩大到其余的协定上,比方 UICollectionViewDataSource。如果在开发中抉择应用 UICollectionView 代替 UITableView 时,这个办法能够让你简直不必批改 viewController 中的任何货色,甚至能够让 Data Source 同时反对两个协定,给予了极大的便利性。

将弱业务逻辑移到 Model 中

注:markdown 对代码块的语法是开始和完结行都要增加:“`, 其中 ` 为 windows 键盘左上角

首先是代码,以下的代码是帮忙用户查找优先事项的列表:

-(void)loadPriorities
{
    NSDate *now = [NSDate date];
    NSString *formatString = @”startDate <= %@ AND endDate >= %@”;
    NSPredicate *predicate = [NSPredicate predicateWithFormat:formatString, now, now];
    NSSet *priorities = [self.user.priorities filteredSetUsingPredicate:predicate];
    self.priorities = [priorities allObjects];
}

然而,如果把这些代码移动到 User 类中会让它变得更加清晰,这时 ViewController.m 中会是:

-(void)loadPriorities
{
    self.priorities = [self.user currentPriorities];
}

而 User + Extensions.m 中则是:

-(NSArray *)currentPriorities
{
    NSDate *now = [NSDate date];
    NSString *formatString = @”startDate <= %@ AND endDate >= %@”;
    NSPredicate *predicate = [NSPredicate predicateWithFormat:formatString, now, now];
    return [[self.priorities filteredSetUsingPredicate:predicate] allObjects];
}

将这些代码移动的根本原因是因为 ViewController.m 是大部分业务逻辑的载体,自身代码的复杂度曾经很高,所以这类跟业务关联不大的代码比方日期转换、图像裁剪、设定过滤器等的操作能够拆散到各自的类中实现,一方面为 viewController 减负,另一方面也能增进代码的复用。

对于这个题目的翻译我斟酌了比拟久的工夫,因为在原文中是 “Move Domain Logic into the Model”,意为“把 畛域逻辑 移到 Model 中”。对于“畛域逻辑 ”一词我进行过讲究,大抵意思为“ 稳固的、不会扭转的逻辑关系 ”,同时在原文中也是应用了 NSPredicate 作为例子援用,而我认为其例子中的代码也是与业务相干的,只不过关联性不大,而且不会轻易改变,所以应用了“ 弱业务逻辑 ”一词代替了“ 畛域逻辑”一词。

把数据处理的逻辑移到服务层

一些代码可能没方法很无效的挪动到 model 中,然而这些代码却和 model 中的代码有清晰的关联,对于这种问题,能够应用 Store。比方在上面的代码中,viewController 须要实现从一个文件中获取一些数据,并对其进行操作:

-(void)readArchive 
{
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSURL *archiveURL = [bundle URLForResource:@”photodata” withExtension:@”bin”];
    NSDate *data = [NSData dataWithContentsOfURL:archiveURL options:0 error:NULL];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    _users = [unarchiver decodeObjectOfClass:[NSArray class] forKey:@”users”];
    _photos = [unarchiver decodeObjectOfClass:[NSArray class] forKey:@”photos”];
    [unarchiver finishDecoding];
}

事实上,view controller 不须要分明怎么实现这些货色,而应该将这些解决交给一个 store object 来实现。

通过对代码进行拆散,可能增进代码复用、对代码进行单元测试、放弃 view controller 整洁等。同时可能让 view controller 更多关注于业务自身的内容,把数据的读取、缓存、新建等操作交给服务层来解决。

把网络服务的逻辑移到 Model 层

这与下面提到的十分相似:不要把网络服务的逻辑放到 view controller 中,而应该把它们寄存到不同的类中。

对于 view controller,应该只是应用一个 completion block 来调用这些办法,而把网络申请、错误处理、缓存解决交给这些类来实现

把解决 view 的代码移到 view 层

无论是应用 Storyboard 还是纯代码编写 view,创立简单的 view 的工作不应该交给 view controller。

比方在须要创立一个日期选择器时,更好的办法是把这些代码放到 DatePickerView 中,而不是放到 ViewController 中,和之前一样,是为了复用和简便。至于如何应用 storyboard 对 view 进行设置这里不再赘述。

Communication(通信)

view controller 中最常产生的就是 通信,包含了和 view 层的通信、和 model 层的通信、和其余 view controller 的通信等。只管这是一个 view controller 必须做的事件,这里仍然有方法可能对代码进行缩减。

对于 view controller 和 view、view controller 和 model 之间的通信曾经存在大量的优良教训,比方应用 KVO 键值模式传值,或者应用 Core Data 中的 NSFetchedResultsController 等。然而,对于 view controller 之间的通信的相干办法却比拟少。

比方在我当初做的我的项目中,一个 view controller 须要依据使用者身份的不同(家长/老师)来对 view controller 的 state 进行不同的设置,而这个 view controller 又在不同的 state 下与不同的 view controller 通信,传递不同的值。在这种状况下 view controller 中的代码会变得相当臃肿和凌乱,所以正确的做法是把这些不同的 state 放到不同的 object 外面,再把它们传给 view controller,让它们依据这个 state 来进行设置和批改,使咱们不再须要被累赘的委托办法搞得非常凌乱。

而在另一种状况下,各个 view controller 之间的跳转逻辑十分复杂,存在着重大的横向依赖,在这种状况下就不合适应用一般的页面跳转模式,而应该应用“中介者模式”,创立一个 coordinator controller,让它来治理页面跳转的逻辑。

论断

事实上当初有各种各样的办法为 view controller 减负,它们无一例外都是向着一个指标后退:写出可保护的代码,只有把这些办法灵活运用,熟记于心,能力真正防止弄出轻便而又难以保护的 view controller。

正文完
 0