美文网首页iOS移动开发你可不能输!研发
iOS中具有复杂UI的模块的设计

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

作者: windgo | 来源:发表于2015-09-11 17:21 被阅读1697次

    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{
        …
    }
    
    

    相关文章

      网友评论

      本文标题:iOS中具有复杂UI的模块的设计

      本文链接:https://www.haomeiwen.com/subject/cumpcttx.html