iOS中具有复杂UI的模块的设计

iOS中复杂UI模块的设计

复杂问题的解决方法

复杂问题的解决方法就是分解,将复杂性一步步分解,复杂问题分解成一系列复杂性较低的可接受的小问题。

开发拥有复杂UI的模块,关键的思路也是分解。

为了更形象,我们拿切土豆丝这件事作为比喻。厨师是怎么切土豆丝的?

完整的土豆通常因为太大,难以吃下,所以我们最常见的土豆的食品,在中国是土豆丝,在国外估计是薯条,其实都是土豆丝。土豆丝的切法,一般来说是先要切片,然后切丝。从两个方向的切,刀的轨迹交织成一个网格,网格里每一个网眼,就是一根土豆丝。

编写程序也一样,对于复杂的功能,需要分解成一根根代码的土豆丝。而且分解的过程也很神奇的和切土豆丝类似,先切片,也就是分层,然后再切丝,也就是划分模块。

1. 切片和分层

iOS开发中的切片,就是分层,常见的是按照MVC(最近还有mvvm什么的)来划分。


控制器:UIViewController的各种子类 ↓(依赖下面的两个层)


视图: UIView子类,Storyboard,Xib文件等


模型:各种表示业务逻辑的类,数据结构的,网络请求的,存储的等等


分层的关键,是解除双向依赖。

两个层之间的代码,上面的层依赖下面的层,下面的层不依赖上面的层;上面层会直接调用下面层中的代码,下面的层不会直接调用上面层中的代码(可以通过kvo,通知,delegate,block等技术间接发送消息)。

在MVC下,就是C层依赖V层,C层依赖M层。解除双向的依赖之后,问题的复杂度就下降了不少。双向依赖容易导致代码死循环,对象引用循环等,在业务的职责上,也容易出现踢皮球的现象。

常常有一种情况,以为自己分层了,其实没有分层,只是分模块。比如,一个登陆模块,你只是分成Login.storyboard, LoginViewController.swift, LoginModel.swift。这不见得是分层,可能只是分了模块。

//LoginViewController.swift
class LoginViewController:UIViewController{
    var loginModel=LoginMode() //控制器
    @IBAction func onLoginButton(button:UIButton!){
        model.login(nameTextField.text,passwordTextField.text,self)
    }
    func loginSucess(){
        //登陆成功之后界面的跳转
    }
}

//LoginModel.swift
class LoginModel {
    func login(name:String,password:String,viewController:LoginViewController) {
        if checkLoginInfo(name,password) == true {
            viewController.loginSucess()
        }
    }
}

因为model和controller发生了相互调用,M和C之间相互依赖了,所以不算分层。分层的写法是这样:

//LoginViewController.swift
class LoginViewController:UIViewController,LoginDelegate{
    var loginModel=LoginMode() //控制器
    @IBAction func onLoginButton(button:UIButton!){
        model.login(nameTextField.text,passwordTextField.text,self)
    }
    func onLoginSuccess(){
        self.loginSucess()
    }

    func loginSucess(){
        //登陆成功之后界面的跳转
    }
}

//LoginDelegate.swift
//使用协议,来解除模型对控制器的依赖
protocol LoginDelegate:class {
    func onLoginSuccess()
}

//LoginModel.swift
class LoginModel {
    weak var delegate:LoginDelegate? //利用代理模式,解除了依赖。
    func login(name:String,password:String) {
        if checkLoginInfo(name,password) == true {
            if let d=delegate {
                d.loginSucess()
            }
        }
    }
}

2. 切丝和功能模块的分解

功能模块的分解,有两个标准,一个是从空间上,一个是从时间上。
假设有这样一个功能,要在一个view里,展示一个班级的信息,包括班级的名称,成立时间,人数,人员列表(可能是学生,也可能是老师),选中人员,展示人员的信息(包括老师的,学生的)

总视图

这样一个功能的UI,从空间上可以分解成:

  • 班级信息
  • 人员列表
  • 人员详细信息
    三部分界面
    其中,人员详细信息部分的界面,从时间上又可以分为:
  • 学生详细信息
  • 教师详细信息
    那么,最终我们分解出的结果如下:

1. 视图层

storyBoard里面包括:
总视图:(对应控制器:SchoolClassViewController)

界面分解我喜欢用的一个技巧,是创建一些占位的试图,到时候子视图直接加入到这些占位视图里面就可以了,子视图的frame,按照占位视图的bounds设置就可以,很方便。

总视图

班级信息视图:(对应控制器:ClassInfoViewController)

班级信息

成员列表视图:(对应控制器:MembersViewController)

成员列表视图

学生详细信息视图:(对应控制器:StudentViewController)

学生详细信息视图

教师详细信息视图:(对应控制器:TeacherViewController)

教师细信息视图.png

2. 控制器层:

//视图总控制器
class SchoolClassViewController:UIViewController {
    @IBOutlet var classInfoViewContaner:UIView! //班级信息占位视图
    @IBOutlet var membersContaner:UIView! //成员列表占位视图
    @IBOutlet var memberDetailContaner:UIView! //成员详细信息占位视图

    var classId=0

    var model:SchoolClassModel!
    func viewDidLoad(){
            model=schoolClassModel(classId);
            //班级信息控制器
            var classInfoViewController
                =ClassInfoViewController() 
            classInfoViewController.model
        =model
            self.addChildViewController(classInfoViewController)
            self.classInfoViewContaner.addSubView(classInfoViewController.view)
            //成员列表控制器
            var membersViewController=MembersViewController()
            membersViewController.model=model.memberList
            self.addChildViewController(membersViewController)
            self.membersContaner.addSubView(membersViewController.view)
    }
    func showMemberDetail(){
        if(model.selectedMember is Student){
                var studentViewController=StudentViewController()
                studentViewController.model=model.selectedMember
                self.addChildViewController(studentViewController)
                self.memberDetailContaner.addSubView(studentViewController.view)    
            }
            else if(model.selectedMember is Teacher){
                var teacherViewController=TeacherViewController()
                teacherViewController.model=model.selectedMember
                self.addChildViewController(teacherViewController)
                self.memberDetailContaner.addSubView(teacherViewController.view)    
            }
    }
}

//班级信息控制器
class ClassInfoViewController:UIViewController{
    weak var model:SchoolClass!
}
//成员列表控制器
class MembersViewController:UIViewController{
    var model:[Member]!
}
//学生详细信息控制器
class StudentViewController:UIViewController{
    var model:Student!
}
//教师详细信息控制器
class TeacherViewController:UIViewController{
    var model:Teacher!
}

3. 模型层

class SchoolClass{
    var name:String!
    var createTime:NSDate!
    var graduateTime:NSDate!
    var memberCount:Int{
        get {
            return count(memberList)
        }
    }
    var memberList=[Member]()
    var selectedMember:Member!
}
class Member{
    var name:String!
}
class Student:Member{
    …
}
class Teacher:Member{
    …
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容