博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS开发笔记--如何更好地使用StoryBoard
阅读量:7190 次
发布时间:2019-06-29

本文共 4250 字,大约阅读时间需要 14 分钟。

原文地址:http://www.cocoachina.com/ios/20161121/18127.html

StoryBoard使用原则:

1. 如果是团队协作开发, 请为每一个屏幕使用一个单独的 StoryBoard,如果你是独立工作, 这依旧是一个好的习惯。

   你在项目里是不是有一个类似于这样的main.storyboard?

323.png

从设计师的角度来看这非常棒: 你可以很容易的看到完整的用户界面和导航流, 这正是使用Interface Builder想要达到的目的。

但是这对于开发者来说, 就可能会存在很多问题:

  • 源码控制: StoryBoard 非常难解决合并时候产生的冲突, 所以单独的StoryBoard会使你在团队工作中变得更加轻松。

  • StoryBoard文件会变得非常臃肿和难以驾驭,你有多少次因为点错而无意中改变了ViewController的约束?

  • 你需要为每一个ViewController分配一个StoryBoard的ID, 这非常容易出错: 因为你每次使用这个veiwcontroller的时候都要硬编码这个ID。

如何连接项目里面的不同的StoryBoard? 这里有两种方法:

  • 使用Xcode7中所提供的StoryBoard Reference方案

  • 通过代码来连接StoryBoard

2. StoryBoard文件与相关的ViewController subclass使用相同的名称。

    这将简化命名的约定, 并且提供给你一些与第三条建议相关的好处。

1
2
let storyboard = UIStoryboard(name: “Main”, bundle: nil)
let homeViewController = storyboard.instantiateViewController(withIdentifier: “HomeViewController”)

这看起来一点都不清晰: 你需要知道这个StoryBoard的名字, 还需要提供这个ViewController在StoryBoard中的ID, 而且你在创建HomeViewController时, 每次都要使用这种方式。

这有一个更好的方式让你用代码在ViewController中使用类方法来初始化它和它所在的StoryBoard:

1
2
3
4
5
6
7
8
class HomeViewController: UIViewController {
     
static func storyboardInstance() -> HomeViewController? { 
         
let storyboard = UIStoryboard(name: String.className(self), 
                                       
bundle: nil) 
return 
         
storyboard.instantiateInitialViewController() as?   
                                                 
HomeViewController 
     
}
}

如果你按照之前的建议来操作, 你就可以避免硬编码 StoryBoard 的名称和实体类的名称.

 

1
let StoryBoard = UIStoryBoard(name: String.className(self), bundle: nil)

 

确保你的StoryBoard的名称和实体类的名称完全相同,否则,当视图引用这个StoryBoard时, 应用程序会崩溃.

这使你代码的可读性更高, 而且可以降低出错率:

 

1
2
3
4
5
6
7
8
class HomeViewController: UIViewController {
     
static func StoryBoardInstance() -> HomeViewController? { 
         
let StoryBoard = UIStoryBoard(name: String.className(self), 
                                       
bundle: nil) 
return 
         
StoryBoard.instantiateInitialViewController() as?   
                                                 
HomeViewController 
     
}
}

 

如果你想通过 instantiateInitialViewController()来访问ViewController, 请确保你在Interface Builder中设置这个ViewController为initialViewController . 如果你在相同的StoryBoard中有多个ViewController, 那么你需要使用instantiateViewController(withIdentifier: _ )

 

初始化这个ViewController的时候仅需要这一句代码:

 

1
let homeViewController = HomeViewController.StoryBoardInstance()

 

区别很明显吧!

你也可是使用类似的方法从nib中初始化view:

 

1
2
3
4
5
6
7
8
9
10
11
12
class LoginView: UIView {
 
     
static func nibInstance() -> LoginView? {
        
if 
let loginView =  
              
Bundle.mainBundle.loadNibNamed(String.className(self),
                               
owner: nil, options: nil)?.first as? 
                               
LoginView { 
              
return 
loginView
        
        
return 
nil 
     
}
}

 

4. 不要让你的项目加载太多StoryBoard segue.

如果你遵循了第一个建议,就不会产生这样的问题。但即使单个StoryBoard中有多个ViewController,使用segue在ViewController之间进行导航也可能也不是个好主意。你需要为每一个segue命名, 这就很容易出错,毕竟使用硬编码的字符串名称始终不是一个好的编程习惯。当你为segue添加少量 “if/else” 或 “switch” 语法的时候, PrepareForSegue方法将会变得丑陋而且不易读。

替代方案是什么呢?

当我们按下导航到下一个ViewController的按钮的时候, 需要为这个按钮添加一个IBAction, 还有初始化这个ViewController的代码. 如果你采用了第三条建议, 那么它实际上就只有一行代码.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@IBAction func didTapHomeButton(_ sender: AnyObject) {
    
if 
let nextViewController =    
                     
NextViewController.storyboardInstance() {
 
   
// initialize all your class properties
   
// homeViewController.property1 = … 
   
// homeViewController.property2 = … 
 
   
// either push or present the nextViewController,
   
// depending on your navigation structure 
 
   
// present present(nextViewController, animated: true, 
      
completion: nil) 
 
   
// or push  
      
navigationController?.pushViewController(nextViewController, 
      
animated: 
true
)
   
}
}

 

5. 神秘的Unwind segue.

 

有的时候我们需要让用户回到前一个屏幕。

 

这里存在另外一个常见的错误:使用一个新的segue导航到前面的ViewController,这将创建一个相同实例的ViewController, 它会加入到视图栈中, 而不是释放当前处于最顶层的ViewController

 

从iOS7开始, Interface Builder 提供给你了 “unwind” 导航栈的方案.

39.png

StoryBoard 里的 Exit outlet

允许你返回到之前任意位置的屏幕,这听起来很简单,但是实际上它还需要一些会让开发者迷惑的额外操作:

  • 通常当你为一个按钮创建一个outlet事件的时候, Interface Builder 将会为你创建对应的代码。在这个时候, 按住”control”从按钮拖动到“Exit” 上面的时候, 对应的代码就会出现在你的项目里。

  • 通常当你为一个按钮创建一个outlet事件的时候, 它会为你的按钮在对应的类中做关联。如果是用 Unwind Segues, 你还需要在目标ViewController中编写代码。

  • prepareForUnwind 方法有 prepareForSegue 方法的全部缺陷. (请参考前面的说明)

 

那更简单的方式是什么样子的呢?

 

那么我们用代码简单的实现一下: 并不用给你的按钮创建一个”Unwind segue”相关的方法, 而是创建一个常规的方法来实现dismissViewController或者popViewController (请参考你自己的导航结构):

 

1
2
3
4
5
6
7
8
9
10
11
@IBAction func didTapBackButton(_ sender: AnyObject) { 
 
// if you use navigation controller, just pop ViewController:
   
      
if 
let nvc = navigationController {   
          
nvc.popViewController(animated: 
true
)
      
else 
// otherwise, dismiss it
      
dismiss(animated: 
true
, completion: nil)  
   
}
}

 

转载于:https://www.cnblogs.com/ios4kerwin/p/6092578.html

你可能感兴趣的文章
洛谷P3379 【模板】最近公共祖先(LCA)
查看>>
获取一个表单字段中多条数据并转化为json格式
查看>>
c#中的变量,属性,字段
查看>>
JS实现延迟载入图片
查看>>
游戏开发中的人工智能
查看>>
Ubuntu 安装BCM 43142无线网卡驱动
查看>>
iOS 疑难杂症 — — UIButton 点击卡顿/延迟
查看>>
免费 官方的ASP.NET MVC电子书-Professional ASP.NET MVC 1.0
查看>>
PL/SQL DEVELOPER
查看>>
HDU-1179-Ollivanders(二分图最大匹配)
查看>>
牛客假日团队赛1 G.Superbull
查看>>
CSS的继承性和层叠性
查看>>
MQTT详解以及在IoT中的应用
查看>>
[python] - 读取文件内容,并输出
查看>>
$.fn.exted({})与$.extend({})区别
查看>>
apache 配置虚拟目录
查看>>
前端开发——HTML学习笔记
查看>>
设计模式-工厂方法模式
查看>>
类的数据成员的 const、static等类型的声明和定义常识
查看>>
银行家算法
查看>>