综合编程

纯Swift项目-Xib | StoryBoard 多人协作技巧

微信扫一扫,分享到朋友圈

纯Swift项目-Xib | StoryBoard 多人协作技巧
0 0

不同于国外, StoryBoard 从面世到如今饱受国内开发者的质疑,质疑的理由很多,什么不利于多人协作啊,隐藏了UI细节啊,出问题不容易测试,降低执行效率啊等等。此文就是针对这些问题的举例和剖析。

StoryBoardXib 有什么区别?

StoryBoardXib 都是用来分离UI样式代码,改善视图代码重用率,增加所见即所得,降低视图测试繁复度的视图系列化工具,

  1. 其中 Xib 以视图 View 为主,
  2. StoryBoard 以控制器 Controller 及其之间的关系,以及和视图 View 的关系为主。

实际使用例子参见 《纯Swift项目-Xib | StoryBoard 设备适配技巧》 或其他 StoryBoard 文章

StoryBoardXib 不利于多人协作, git 合并代码容易冲突,且难以处理?

这个是诋毁 StoryBoard 最多的理由,也是 看上去 最充分的理由。最显著的就是下图这种失败的例子。

在一个 Storyboard 中,大量的 Controller 控制器和 Segue 连线彰显着错综复杂的UI关系,使人望而生畏或者难以维护。

但这并不应该是 Storyboard 的锅,仅仅是使用者对工具的滥用!

没错,就是 滥用 ,无论是 Storyboard 也好,纯代码也罢,它们的本质都是工具,工具本身没有正义或邪恶,影响工具的是使用者。哪怕是用纯代码开发,如果没有命名规范,肆意的嵌套 if ,不遵守MVC或者MVVM等开发模式,不区分开发环境与生产环境,这样写出来的代码又何谈可维护性,和多人协作呢?

那么反过来说,如何使用 Storyboard 才不算滥用?

避免滥用,最好的方法就是定制规范,就好像代码中的诸多规范一样。每个团队可能有自己不同的喜好,我在此抛砖引玉,列出我们团队使用 Storyboard 的规范,供大家参考。

每个模块独立 Storyboard 每个 Storyboard 只应该有一个主VC和同页的子VC,主VC不应存在2个以上
  1. 一个项目中, Storyboard 不该是孤立存在的,应该像 MVP 模式那样,每个页面都有独立的 Storyboard ,每个 Storyboard 只应该有一个主 VC 和同页的子 VC ,主 VC 不应存在2个以上。(绝大多数情况下,一个 Storyboard 上只应该有一个 VC
  2. 页面间的 Segue 连线应该使用 Stroyboard Reference SceneUITabBarController 的子页因为复杂度应该当成主 VC 处置
  3. 视图的初始样式应尽量在 Storyboard 上属性面板中设置,非极特殊情况,布局也应在 Storyboard 上使用各种约束配合完成。这样有利于视图样式和视图代码分离,有利于视图代码重用性和兼容性提高。
  4. 对于逻辑复杂的 VC ,应添加Object对象,并绑定相应的类来分离逻辑代码。
  5. 对于圆角,背景色,阴影等 CALayer 的样式,应该使用扩展或子类化实例的形式,使用 @IBInspectable 属性关键字,在 Storyboard 属性面板中设定初始样式。
  6. 对于自定义视图,应使用 @IBDesignable 关键字保障在在 Storyboard 上所见即所得!

使用以上原则,只要任务分工合理,基本上不存在多人同时修改同一个 Storyboard 的情况,就算配合失误偶然发生,精简的 Storyboard 其代码量也不大,借助文件比较工具很容易就能处理git冲突。

说到底,臃肿的 Storyboard 和臃肿的 ViewController 一样,都是难以维护且容易 git 冲突的。唯一的解决方案就是有节制的使用工具。

StoryBoardXib 隐藏了UI细节,且容易导致 ViewController 臃肿?

与其说 StoryBoardXib 隐藏了UI细节,倒不如说苹果是希望通过他们来引导开发者正确的使用 视图控制器 ,他们创建视图实例的时候都是通过

required init?(coder aDecoder: NSCoder) {
    
    }
复制代码

构造方法创建视图实例。所有初始样式都是在属性面板中设置的值,通过

func setValue(_ value: Any?, forUndefinedKey key: String) {
        ......
    }
复制代码

来赋值给视图对应的属性。

至于说导致 ViewController 臃肿,更是荒谬, StoryBoard 提供了多种方案来分离代码,只不过很多人不知道而已。

拿美团的主页UI举例

这样的首页较为复杂,正常布局的话需要多个 CollectionView 和一个 UITableView

如果这些视图的 Delegate 都由 ViewController 来实现,自然显得臃肿且混乱。

一般手写派会分出3个 ChildViewController 来解决臃肿问题,难道 Storyboard 就做不到么?

答案是否定的,很早的版本,苹果就给出了上图中的解决方案。一个占位的容器视图指向子控制器的 Embed Segue

按住 Control 键连线到想要包含的子控制器,占位视图的实例==子控制器的 view (子控制器根视图)

选择 Embed 连线方式后,子控制器 的尺寸变化成跟占位视图一样的尺寸

这样我们可以将功能图标的 CollectionView 的代码放到这第一个子控制器上, CollectionViewDelegateCollectionViewDataSource 等代码也由子控制器实现

同理,优惠专区可以再添加一个 Container View ,指向第二个子控制器。

通过 Container View 创建的 ChildViewController 如何与主 ViewController 传参或互相调用?

ChildViewController 可以通过 self.parent(Swift)|| self.parentViewController(OC)来拿到主 ViewController 的实例。 主 ViewController 可以通过 self.chilren(Swift) || self.childViewControllers(OC)来拿到 ChildViewController 的实例,它是一个数组,顺序等同于占位视图再视图层次中的顺序。

值得一提的是,通过此种方式创建的 ChildViewController ,其构造方法晚于主 ViewController ,但生命周期中的 viewDidLoad 则早于主 ViewController , 因此在 ChildViewController 中的 viewDidLoad 方法中, self.parentnil ,这时不能拿到主 ViewController 实例。如果需要在初始化的时候拿到主 ViewController 的实例,则应该在主 ViewController``viewDidLoad 方法中,调用 ChildViewController 的特定方法,把 self 当参数传过去。

  • 除此之外还可以使用Object对象

将它添加到控制器之上。

它的本质是一个继承自NSObject的子类,我们完全可以把它当成一个小功能模块的控制器。

class FeaturesController: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
    
    @IBOutlet weak var collectionView:UICollectionView!
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
    }
}
复制代码

Storyboard 上选中这个 Object ,绑定上面的类

右键这个
Object

,在弹出的菜单中连线

右键 CollectionView 设置 DelegateDataSource 等的连线

在主 ViewController 中如需调用这个模块的方法或者传参

class HomeController: UIViewController {
    
    @IBOutlet weak var featuresController:FeaturesController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        featuresController.datas = [....]
        featuresController.collectionView.reloadData()
    }
    
}
复制代码

完成连线,同理,如果一个页面需要多个子模块,可以在 Storyboard 上拖入多个 Object ,并绑定不同的模块控制类,相对于占位的 Container ViewChildViewController 方法, Object 方法在传参或互相调用方面,更加简便。缺点是没有 ChildViewController 的生命周期方法,如需使用 viewWillAppear 等,需要在主 ViewControllerviewWillAppear 中,调用 Object 的自定义方法。

通过上面的2种方法不难看出,并非是 Storyboard 造成 ViewController 代码臃肿,而是因为设计不当导致,就算你不用 Storyboard ,把所有功能都写在一个 ViewController 里一样臃肿。这都是使用者决定的,并非 Storyboard 的责任!

StoryBoardXib 出了问题不容易测试?

这个问题其实问的很模糊,我也是咨询了很多人才知道,他们所谓的问题不容易测试,是指如下两种情况:

  1. 修改或删除 @IBOutlet 的变量名时,对应的 Storyboard 上未做处理,导致运行时崩溃,崩溃内容看不懂!

StoryBoardXib 降低执行效率?

(未完待续。。。。)

稀土掘金
感谢您的支持!

    Scala: What's wrong with my method?

    上一篇

    GraphQL Subscriptions with a Standalone Rails API and React

    下一篇

    您也可能喜欢

    评论已经被关闭。

    插入图片

    热门分类