Apple在Xcode 8中对Interface Builder进行了很大的改进。使用大小类变得更加直观,缩放故事板的能力非常方便,Interface Builder中的完整预览功能非常棒。对于那些对使用Interface Builder犹豫不决的人来说,这可能会成为一个交易破坏者。
另一方面,许多开发人员在构建具有复杂导航功能的大型多屏幕应用程序时仍然会遇到一些界面问题。
在本文中,我将在您处理项目中的故事板和笔尖时分享一些好的做法。您之前使用的是Interface Builder,或者您只是向这个方向迈出了第一步,这些提示可能对您有用。
1.如果您在团队中工作,请为每个屏幕使用单独的故事板。如果你独自工作,这仍然是一个好习惯。
您的项目中是否有一个与此类似的main.storyboard文件?
image.png从设计师的角度来看,这看起来很不错:您可以轻松查看完整的UI和导航流程。这正是Interface Builder的创建方式。
但对开发人员而言,这可能会导致多个问题。
- 源代码控制:故事板合并冲突很难解决,因此简单地在单独的故事板中工作将使您的团队生活更轻松。
- 故事板文件变得沉重且难以导航。有多少次您在错误的ViewController中单击一次无意中更改了约束?
- 您需要为每个ViewController分配storyboard ID,这很容易出错:每次要在代码中使用ViewController时都需要对此ID进行硬编码
如何在项目中连接不同的故事板?有两种方法。
1.使用Xcode 7中引入的故事板引用
2.在代码中连接故事板。
你可以阅读更多关于第一种方式在这里。
我将介绍第二种方式,因为它仍然常用于复杂的项目。
2.对storyboard文件和关联的viewController子类使用相同的名称。
这将简化命名约定,并在建议#3中为您提供一些好处。
3.在其UIViewController子类中初始化storyboard。
在代码中初始化基于storyboard的viewController时,我经常会看到以下代码:
let storyboard = UIStoryboard(name: “Main”, bundle: nil)
let homeViewController = storyboard.instantiateViewController(withIdentifier: “HomeViewController”)
这看起来并不清楚:您需要命名故事板,您需要提供viewController故事板ID,并且每次创建HomeViewController时都需要使用此模式。
更好的方法是将此代码移动到viewController子类中,并使用静态方法使用storyboard初始化它:
class HomeViewController: UIViewController {
static func storyboardInstance() -> HomeViewController? {
let storyboard = UIStoryboard(name:
“HomeViewController”, bundle: nil) return
storyboard.instantiateInitialViewController() as?
HomeViewController
}
}
如果您遵循以前的建议,则可以避免硬键入故事板名称并使用className:
let storyboard = UIStoryboard(name: String.className(self), bundle: nil)
确保您的故事板文件与实际类名称相同。否则,当您尝试创建对此故事板的引用时,应用程序将崩溃。
这使您的代码更具可读性并且更不容易出错:
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中有多个viewControllers,则必须使用instantiateViewController(withIdentifier:_)
现在,当你需要初始化这个viewController时,它将是一个单行程序:
let homeViewController = HomeViewController.storyboardInstance()
很清楚,对吗?
您可以使用相同的方法从nib初始化视图:
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.不要使用故事板segues重载项目
如果您遵循第一个建议,情况就不会如此。但即使您在单个Storyboard中有多个viewControllers,使用segues在viewControllers之间导航也许不是一个好主意:
- 你需要为每个segue命名,仅此一个就容易出错。硬编码长字符串名称总是一个糟糕的编程习惯。
- 当您使用“if / else”或“switch”语句添加一些segues时,PrepareForSegue方法将变得难看并且不可读。
有什么选择?当您想要按下按钮导航到下一个viewController时,只需为此按钮添加一个IBAction,并在代码中初始化此viewController:当您采用建议#3时,它实际上是一行代码。
@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。
从iOS 7开始,Interface Builder为您提供了“展开”导航堆栈的方法。
Exit outlet in StoryboardUnwind segue允许您指定返回上一屏幕的目的地。这听起来很简单,但在实践中它需要一些额外的步骤,只会让开发人员感到困惑:
- 通常,当您为按钮创建动作插座时,Interface Builder将为您创建代码。在这种情况下,从按钮拖动到“退出”出口是期望代码已经在您的项目中。
- 通常,当您为按钮创建动作插座时,它会将代码放在拥有该按钮的同一个类中。对于Unwind Segues,您需要在目标视图控制器中编写代码。
- prepareForUnwind方法的所有缺点prepareForSegue方法(见前面的建议)
什么是更简单的方法?
在代码中执行它更简单:不是为按钮创建“展开”动作,而是创建常规IBAction并使用dismissViewController或popViewController(取决于您的导航结构):
@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://medium.com/@stasost/xcode-a-better-way-to-deal-with-storyboards-8b6a8b504c06
作者:Stan Ostrovskiy
网友评论