内容简介:翻译、修改自objc.io原文链接:导语
翻译、修改自objc.io
原文链接: Lighter View Controller
导语
view controller通常是一个项目中最庞大的文件,因为它里面经常包含了不属于它的代码,同时这也使它成为代码中最难以重用的部分。所以为view controller瘦身,让其中的代码复用性更强,把相关代码放到正确的地方显得尤其重要。
将Data Source和其他协议分离
为view controller瘦身最有效的方法就是把UITableViewDataSource中的代码移动到相关的类中,具体的方法可以参阅 《iOS应用开发 简明TableView》 中的相关实现。
而更进一步,不只是TableView,这个方法可以扩展到其他的协议上,比如UICollectionViewDataSource。如果在开发中选择使用UICollectionView代替UITableView时,这个方法可以让你几乎不用修改viewController中的任何东西,甚至可以让Data Source同时支持两个协议,给予了极大的便利性。
将弱业务逻辑移到Model中
首先是代码,以下的代码是帮助用户查找优先事项的列表:
-(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。
想了解更多内容可以查看 我的主页
作者:Dywane
链接:https://www.jianshu.com/p/cdf05c8dc3a5
以上所述就是小编给大家介绍的《iOS开发 简化view controller》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- JAVA开发之简化Dao层、提高开发效率(三)
- 在事务中使用闭包函数简化开发
- 容器平台加速并简化云应用开发
- Dapr 是如何简化微服务的开发和部署
- 巧用模板模式和工厂模式简化开发工作
- Firefox 支持 Web 组件技术,简化复杂网站开发
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。