大家是用Interface Builder还是手工敲界面的呢?ViewController 究竟应该扮演怎样的角色?

2012-05-22 22:38:25 +08:00
 Elfe
刚开始玩iOS。发觉StoryBoard的拖拖拽拽做得还真不错。
不过,按我以前的习惯,肯定是手敲代码的。我只是尚不确定究竟该敲xml格式的 .storyboard 文件,还是应该敲 .h .m 文件把界面用代码给编出来。(粗略的看了看,我比较倾向于敲 .storyboard,就像我以前写 WPF 程序时手工敲 xmal 一样。不过对于老版本的,刚才看了眼.nib,这个xml的可读性也太差了,还是用 .h/.m 代码为好。 )

直接敲代码的好处,主要是:
1)效率高,光操作键盘当然比键盘+鼠标要高效
2)代码完全在自己控制之下,尤其适用于有代码洁癖的人
3)对程序实现有更好的了解

所以当我得知接手的项目都是用手工敲的代码来做UI的时候,还挺高兴。
可现在仔细一看代码,有点发蒙:怎么命名为XXXiewController的类里好多都是画UI的代码呢?例如:
UILabel* headerTitle = [[UILabel alloc] initWithFrame:CGRectMake(61, 0, 198, 45)];
难道它们不应该被放置在XXXView的类中?
再仔细看看,那些XXXView的类中也有很多画UI的代码。
这也太混乱了吧?

这么说来,使用拖拖拽拽的方式,或许至少有一大好处,就是自动帮你运用了MVC模式,确保代码大的结构上没有问题。我接手的这个项目,自己写,结果就写的混乱了。

还是我对Cocoa 中 MVC 中的 C 中的 ViewController 理解有误?
我原以为,在MVC/MVP/MVVM中,V应该只包含界面相关的代码。最理想的,应该没有任何的 code behind (也就是说所有的V的代码都在 xml 文件中),除非这是纯粹界面相关的逻辑。而除了纯粹界面相关的逻辑,其它界面逻辑代码都应该在 ViewController 中。ViewController 不应该包含任何界面细节的代码。如果不使用.nib 或 .storyboard,那等同的内容就应该在 XXXView 的.m 文件中实现,不应该放在 XXXViewController 中。

啰啰嗦嗦写了一大堆,就是这么三个问题:
1)上面这一段,我对ViewController角色的理解,正确么?
2)你是用 InterfaceBuilder 拖拖拽拽,还是手工敲UI?理由?
3)如果手工敲UI,是敲xml 文件还是.h/.m文件?等同于原来.nib 或 .storyboard 的代码分别在哪些文件中实现?
10808 次点击
所在节点    iDev
29 条回复
Livid
2012-05-22 23:48:21 +08:00
真心希望 V2EX 上这样的主题更多一些。

关于你的 3 个问题我的一些粗浅理解。

1. 就如名字所暗示的那样,ViewController 的主要角色是 controller,但是它提供的 loadView 这个方法就是让你可以通过代码的方式来写界面,包括那些很丑的具体坐标填写,和手工的 autoresizingMask 设置。

2. Apple 的大部分应用都是用 IB,也有少部分用的是代码。Facebook 基本上用的是代码。游戏类基本是代码。所以,如果你用了一个在交互上觉得有亮点的应用,你可以用 iTunes 把它下载下来,然后把那个 ipa 弄到桌面,unzip(ipa 其实就是 zip 改个 ext),然后看里面有没有 xib。

3. 手工敲代码的话,肯定是在 .m 的 loadView 里。.nib 和 .storyboard 可以完全不用。你可以具体看看 UIViewController 定义的各个方法在文档里的说明。Apple 的文档个人觉得,还是比 MSDN 要好一些。:P
lldong
2012-05-23 01:08:37 +08:00
Mac上xib+CocoaBinding很方便,不過iOS不支持,還有xib在版本控制衝突的時候比較麻煩,所以iOS上多數用代碼寫,也可以先用xib拖好佈局然後用nib2objc轉成代碼,還有就是用DCIntrospect實時查看修改界面元素的位置和屬性,減少build&run的次數 https://github.com/domesticcatsoftware/DCIntrospect
paloalto
2012-05-23 01:35:45 +08:00
刚接触StoryBoard,感觉对于我这种菜鸟还是挺方便的。
Kai
2012-05-23 01:54:48 +08:00
其实我觉得用心在如何实现功能上比较靠谱,IB + Code,或多或少都会用到,只要程序实现的漂亮,哪个部分都是好的。
iEggache
2012-05-23 03:07:55 +08:00
能用InterfaceBuilder的时候尽量用,别和自己过不去,而且手工敲效率低还容易产生各种bug....
Elfe
2012-05-23 07:03:28 +08:00
看来还是喜欢 IB 的多一些啊。

@Livid 关于viewController 的 LoadView 方法的运用,我还是有不同理解。
我觉得若我有一个AView,它可以纵向也可以横向,它可以允许外层有导航栏也可以没有,那在相应的 ViewController loadView 函数中,就需要设置它的纵横属性,设置它的最外围的 Rect。
但是,这个 view 中有一个 label,有一个 button,有一个 BSubView,这些东西原本是该在 .nib 中的,去掉了 .nib, 也还是应该单独写个 AView 类来画出来吧,怎么可以全部放到 iewController 里呢?
现在我看到的代码,就是有 BSubView.h/.m, 可是没有 AView.h/.m,所有关于 AView 的实现全部都在 AViewController 中。

View 和 ViewController 的职责界限到底在哪里呢?我觉得 ViewController 中除了告诉对应的 view 一个最外围坐标(也就是,把这个 view 恰当的 load 起来),就不该出现任何和坐标相关的代码了。
Elfe
2012-05-23 07:15:11 +08:00
@iEggache 看了下,如果是 .nib 的话手工敲出来还真不太可能。

对比 iOS 和 微软的 WPF,我感觉:
一方面,XCode 的IB做得真好(我用的是最新版的写 storyboard 的),拖拽很方便。相比之下,VisualStudio 内的 Xaml Designer 真是悲剧,以至于要么是做界面设计的人用 Expression Blend 画,要么是作开发的直接敲 xml 文件画。
另一方面,WPF 中定义界面的 .xaml 文件真是强大,我光敲xml文件就能很迅速的作出好看灵活功能强大的界面,比用 .cs 代码方便很多。相比之下,.nib 真是弱爆了,完全不是给人读/写的嘛。粗粗一看觉得 .storyboard 可读性提高不少,不过看来还是没到可以手工写的地步。
adow
2012-05-23 07:38:58 +08:00
我以前写wpf/silverlight时,也几乎全部使用手工写xaml代码。我的感觉是这层view太灵活和强大,设计器反而拖累了他使得无法很方便实现我们各种折腾的效果,另外xaml设计成手工写代码也很适合的语言,就和我们写html一样,太灵活我们都写html/css而不是用dw之类的设计器。所以手写view只感觉高效。而在xib中,我不觉得写他的xml方便,只是绝得这是可行的,在controller中大多是引用操作xib中的ui,有时也得自己创建或者加载控件,也绝得从职责分离的角度说不如wpf那样纯粹。
Livid
2012-05-23 08:15:09 +08:00
@Elfe 如果一个 viewController 的 view 不需要特殊定制的话,你确实可以不需要有 AView.h/m,你只要在 loadView 里:

UIView * aView = [UIView new];
self.view = aView;

然后按钮和图片就:

[aView addSubview:button];
Smartype
2012-05-23 08:19:40 +08:00
@Elfe 同意,不应该在loadView 里面load sub views. loadView 是让你load这个view当然唯一的view的。

试想你在这里load subviews,添加到[self view], 你都没有办法layoutSubviews!

所以正确的做法是subclass一个UIView。然后在VC里面load它
Smartype
2012-05-23 08:24:38 +08:00
@Livid 呵呵,当然"可以"。但是不好。
对于使用代码还是xib,我个人认为和界面复杂度/标准度有关。
试想,path会用xib?
我如果要简单的支持ipad+iphone,我也会是直接写代码,重复工作少,便于维护
damngood
2012-05-23 08:47:28 +08:00
收藏, 刚好最近也在就项目思考这个问题
以前也是所有的view层的构建都放在loadView/viewDidLoad这些方法里面, 看上去确实有OP提到的问题。
现在也是倾向于单独创建一个XXView出来, 然后用tag来定位其中的子View, 这样的话Controller会看起来纯粹点。
wtl
2012-05-23 09:19:26 +08:00
@damngood 就我个人粗浅的理解,controller就是大杂烩,各种view都塞进去。

如果controller对应的是单个view,再在view上添加各种子view,其实这个单个的view如果再有个model成员变量的话,就是一个controller。

当然,如果你自定义的view是可以到处重用的,那另说。 如果只是真对某个controller, 这样的分割,意义并不大。
wtl
2012-05-23 09:31:05 +08:00
其实view本身就是mvc的体现,比如一个slider,view部分可以由一个barView,一个thumbView组成,model包含backgroundImage,thumbImage, selectedValue, minValue, maxValue等组成。然后slider根据model绘制各种子view,处理响应点击触摸事件。

对于slider自身来说,它自己就是controller,糅合各种元素和逻辑。但是对于外界的使用者,它就是一个view。
damngood
2012-05-23 10:34:44 +08:00
@wtl 对, 可重用性也是考量因素之一

我理解中的Controller主要是针对应用业务逻辑的处理, 然后根据处理结果更新View层, 主线是逻辑处理, View层的更新代码应该越精简越好。如果可以的话XXView甚至可以把所有的其中子View的更新的处理通过API供Controller调用, 当然这样看上去极端了点, 自己也没有这样尝试过, 还只是一些想法。:)

对View自己也有自己的小世界, 但是在App层整体来看, 它还是归于MVC里面V这个角色
Yonsm
2012-05-23 10:50:55 +08:00
敲代码方式写出来的代码,可以比较方便地支持各种横屏、竖屏和iPhone、iPad。用IB的话,可能要同时维护2份或4份xib,同一功能的代码重复了,这事我最反感的。

IB有些属性没法设置,最奇怪的是竟然连 autoResizingMask也无法设置,这个可以设置的话,对于支持横屏竖屏可以省不少事(当然你可以说IBOutlet然后在.m中只设置这个属性)。
lex
2012-05-23 13:30:52 +08:00
@Yonsm 是吗?我以为这个面板是设置 autoResizing 的。。
Elfe
2012-05-23 23:45:55 +08:00
恩,@Smartype 和我的理解是一致的。我上面说的这个例子,在我看来,要么建一个 AView 把 label, button 和 BSubView 都放进去,要么,干脆让 BSubView 本身就包含 label 和 button, 并且有设置是否显示 label/button 的属性,ViewController 只需要设两个布尔值即可。

像 @wtl 举的关于 slider 的例子也一样,对于外边的创建、调用来说,只需要管一个 View。不过,在 slider 的内部实现,它的 viewController 到底该不该包含计算数值、位置的代码,还真是不太好说。感觉 slider 有那么一点点特殊,因为它的一大部分逻辑就是和位置相关的。

粗粗看了眼 @lldong 提到的 nib2objc,忽然想到,是不是对用这类工具转化得到的代码,最方便的处理方式就是一古脑儿塞到 viewController 的 loadView 函数中呢?

谢谢 @Yonsm 让我知道为啥 IB 很好用可还是有不少人会选择手写。

@adow 握个手!xaml 真是很强大。你也是先前做 WPF/Silverlight 的呀,看来我以后有问题可以盯着你问。我从 VS 转到 XCode,还很不适应呢。
Gal3rielol
2012-05-24 09:37:11 +08:00
如果不使用nib,等同代码应该放在viewcontroller中的loadview:中。
并且view hierarchy就是应该在view controller中构建并控制的,比如说想让一个界面元素隐藏,这个工作明显应该让vc来做。

如果是刚接触这个平台,我推荐使用纯代码的方式构建界面,当对整个平台有一定的了解的时候再用interface builder.
Elfe
2012-05-24 11:53:17 +08:00
找到一本书 iPhone SDK Application Development (《AppStore 掘金》),代码全都是手工写的。看了眼它的例子,还真是所有界面相关的内容都在 loadView 中,根本就没有写 View 的子类
那看来,ViewController 虽然名字中带个“controller”,其实是更应该是 MVC 中的 V,包含 View 中的那些 code behind (不知道这个词在 iOS 开发中应该怎么说,在 WPF/Silverlight的世界,就是指对应于 .xaml 文件的 .cs 文件中的内容)。

这样看待 ViewController,那对于简单的不值得单独写一个 View 子类的V (并且也没有 .nib 来画界面),让 loadView 包含各种位置、大小之类的代码也可以接受。我刚又去看了眼我接手的项目,发现:
对简单的要重用的小控键,只有 View 子类;
对复杂的但不重用的大界面,只有 ViewController 子类;
项目中暂时没有找到同时存在对应的 View 和 ViewController。
我想如果有复杂的但是又需要重用的控键,比如 @wtl 举的 slider 的例子,就应该同时有 View 和 ViewController 吧,当然对于外界调用来说只需知道一个 View。

好了,不纠缠在这些概念上了。虽然还是觉得在一个名为Controller的类中看到大量位置数值的代码,很不符合我的审美,可至少知道了它的原委,换个角度来看也可以理解了。Coding 去啦⋯⋯

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/36961

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX