iOS开发 - 一个天真的搜索控制器的独白

文/Azen(简书作者)
原文链接:http://www.jianshu.com/p/6d5327111511
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

正文


一、关于横向模块开发

团队型项目开发中,往往是根据功能模块进行开发任务分工的,如:商品模块、社交模块、设置模块等等,但是模块与模块之间,往往存在着一些横向的、通用的小功能,如:日历选择、出发地选择以及本文要谈到的搜索控制器。
做横向模块和封装框架是一样一样的,最最重要的,是接口的设计。如何增强模块的通用性、减少侵入性,让该模块的使用者用的爽,在设计接口的时候需要充分考虑的。

  • 所谓通用性,是指能在多大程度上让别人用。做的最好的应该是苹果的UITableView。UITableView被称为“SB控件”,因为他不用知道自己展示什么内容,不用知道自己需要展示多少行,一切差异化的东西,全部通过代理来获取,所以他能拥有极其强大的通用性,所有想要做表格型展示的人都能用。

    • 然而,通用性也有它的弊端,就是会额外增加使用该控件的开发人员的工作量。
    • 假设项目中用到的所有tableView,都有相同的tableHeaderView、相同的numberOfSection & numberOfRow。如果还是用官方原生的UITableView,那我们每次使用,都需要写相同的、重复的代码来设置。
    • 这个时候我们就应该通过二次封装的方式,主动降低通用性,来减少重复代码。
    • 所以,不管是产品还是技术,没有绝对好的方案,只有在一定范围内,最适用的方案。技术就是权衡。
  • 所谓侵入性,是指别人用了你的控件,一旦不想继续用了,要花费的调整代码的精力会不会非常大。推荐杰哥的MJExtension,这个神一样的框架基本上做到了零侵入性。

OK,装B完毕,咱们来看看这个“搜索控制器”的需求。

二、需求

  1. 不同板块相同需求
    1.1 右上角的“搜索”按钮title,没输入关键词,展示“取消”;输入了关键词,展示“搜索”
    1.2 没搜索到结果,关键词高亮现实

    统一:搜索无结果.gif

    1.3 搜索有结果,展示搜索结果
    1.4 请求数据时,转菊花
  2. 不同板块不同需求
    2.1 板块一

    板块一:刚进来没点搜索.gif

    2.2 板块二

    板块二:刚进来没点搜索.gif

    2.3 板块三

    板块三:刚进来没点搜索.gif

三、思考

问题:

  • UI层面,不同的元素如何如何处理?
    • 如:搜索框的placeHolder,是让使用者传字符串进来?还是传type进来,我们根据传进来的type,在控制器内设置不同placeholder?
  • 数据层面,请求数据的逻辑在搜索控制器内部写死?还是让外部把搜索结果传进来?

  • 其他

    • 接口方法设计为类似MBProgressHUD的“+ (void)showXXXXX”型,还是设计成普通的返回一个实例控制器,让使用者决定何时弹出该控制器?

结论

  • UI层面的差异比较简单明了,不涉及到后续一些东西,在控制器内部设置比较方便,采用传入type方式
  • 数据层面的东西(包括网络请求和本地持久化),逻辑不那么简单直接,而且不同板块应该请求哪些接口、本地存储存在什么地方,显然负责做该板块的同学比我们更清楚,所以最好的办法是把请求数据之类的事情交给外部去做,我们只要提供一个方法,让外部能把请求好的数据转换成字符串数组传进来,我们负责展示就好。
  • "+ (void)showXXX"方法用起来显然更爽,而且我们不会把过多的细节暴漏给该控制器的使用者,可以限制使用者的权限,防止使用者进行一些不恰当的操作导致崩溃(顺便插一句,相对于window来说,mac OS 就是这样做的。不用关心什么杀毒软件、硬盘分区之类的破事儿,写代码就安心写代码,做设计就安心做设计,系统方面的东西可以不用关心...这也是macOS用起来更爽的原因之一)

思路整理

现在,咱们想做这样一个搜索控制器:

  1. 足够封闭,不把搜索控制器对象返还给使用者
  2. 有足够的通用性,请求数据、数据存储等事情交给调用者处理,我们的搜索控制器只负责数据展示
    1.1 这意味着,我们需要告诉调用者(数据逆传):

    • 什么时候应该请求网络数据(点击了搜索按钮)
    • 什么时候应该清空本地缓存(点击了清除按钮)
    • 用户点击了哪条搜索结果

    1.2 调用者需要告诉我们(数据顺传):

    • 请求回来的数据是什么
  3. 请注意,通常我们进行数据顺传的方式,是拿到某个控制器,点出来他的属性,并进行赋值;而咱们想要的效果,是最大程度限制调用者的权限,不让调用者拿到咱们的搜索控制器(意味着不能点出来)的同时,最好限制调用者只能通过咱们给定的方法告诉咱们搜索结果(不让调用者拿到搜索控制器的属性)。

怎么办?有什么办法能不返还给调用者一个对象,只返还给调用者一个方法?答案是block。
数据逆传方面,个人也还是非常喜欢block。因为相比于代理,block能够让代码实现“高聚合、低耦合”,不用跳来跳去的找代码,维护起来更方便。
(下一篇:一个复杂的首页的独白中,咱们会用到将代理和数据源方法,全都变成block的tableView)

四、上代码吧

这篇文章主要讲的,其实还是接口设计。所以代码就只贴头文件吧,源码丢在Github上了嗯(源码传送门)...如果觉得还有那么点小启发的话,记得顺手点星哦^_^

 1 文/Azen(简书作者)
 2 原文链接:http://www.jianshu.com/p/6d5327111511
 3 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
 4 
 5 //
 6 //  AZXSearchController.h
 7 //  AZXSearchControllerDemo
 8 //
 9 //  Created by Azen.Xu on 15/12/5.
10 //  Copyright © 2015年 Azen.Xu. All rights reserved.
11 //
12 
13 #import <UIKit/UIKit.h>
14 
15 typedef NS_ENUM(NSInteger, AZXSearchControllerType) //  搜索控制器类型
16 {
17     AZXSearchControllerTypePartOne = 1 << 0,   //  板块一
18     AZXSearchControllerTypePartTwo = 1 << 1,   //  板块二
19     AZXSearchControllerTypePartThree = 1 << 2  //  板块三
20 };
21 
22 typedef NS_ENUM(NSInteger, AZXSearchFunctionType)   //  点击事件类型
23 {
24     AZXSearchFunctionTypeClear = 1 << 0,    //  点击了"清除搜索历史"按钮
25     AZXSearchFunctionTypeSearch = 1 << 1,   //  点击了"搜索"按钮
26     AZXSearchFunctionTypeSearchArray = 1 << 2,    //  点选了搜索结果列表
27     AZXSearchFunctionTypeHotArray = 1 << 3,       //  点选了热门搜索列表
28     AZXSearchFunctionTypeHistoryArray = 1 << 4,   //  点选了历史搜索列表
29     AZXSearchFunctionTypeCreatTagForDiscover = 1 << 5   //  点选了创建标签
30 };
31 
32 typedef void(^AZXSearchCallBack)(AZXSearchFunctionType selectedType , NSInteger selectedRowIndex , NSString *resultString); //  点击回调 参数一:点击事件类型 参数二:选中行号 参数三:选中文字
33 typedef void(^AZXSearchSetNewArrayHandle)(NSArray *newArray);   //  通过此block传递搜索结果字符串数组
34 
35 
36 @interface AZXSearchController : UIViewController
37 
38 /**
39  *  根据type创建不同展示样式的搜索控制器,返回搜索结果handleArray
40  *
41  *  @param fromController 来源控制器
42  *  @param hotArray       热门搜索stringArray
43  *  @param hisArray       历史搜索stringArray
44  *  @param type           样式枚举
45  *  @param calBack        回调 - 数据请求成功后请为handleStringArray重新赋值
46  *
47  *  @return 搜索结果handelArray
48  */
49 + (AZXSearchSetNewArrayHandle)showSearchControllerFromController :(UIViewController *)fromController
50                                                withHotModelArray :(NSArray *)hotArray
51                                                    hisModelArray :(NSArray *)hisArray
52                                                             type :(AZXSearchControllerType)type
53                                                         callBack :(AZXSearchCallBack)callBack;
54 
55 @end
View Code

 

posted @ 2016-03-25 10:53  FMDN  阅读(236)  评论(0编辑  收藏  举报