大家是用Interface Builder还是手工敲界面的呢?ViewController 究竟应该扮演怎样的角色? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
Elfe
V2EX    iDev

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

  •  
  •   Elfe 2012-05-22 22:38:25 +08:00 11463 次点击
    这是一个创建于 4938 天前的主题,其中的信息可能已经有所发展或是发生改变。
    刚开始玩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 的代码分别在哪些文件中实现?
    29 条回复    1970-01-01 08:00:00 +08:00
    Livid
        1
    Livid  
    MOD
    PRO
       2012-05-22 23:48:21 +08:00   2
    真心希望 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
        2
    lldong  
       2012-05-23 01:08:37 +08:00   3
    Mac上xib+CocoaBinding很方便,不iOS不支持,有xib在版本控制突的候比麻,所以iOS上多用代,也可以先用xib拖好局然後用nib2objc成代,有就是用DCIntrospect查看修改界面元素的位置和性,少build&run的次 https://github.com/domesticcatsoftwareDCIntrospect
    paloalto
        3
    paloalto  
       2012-05-23 01:35:45 +08:00
    刚接触StoryBoard,感觉对于我这种菜鸟还是挺方便的。
    Kai
        4
    Kai  
       2012-05-23 01:54:48 +08:00
    其实我觉得用心在如何实现功能上比较靠谱,IB + Code,或多或少都会用到,只要程序实现的漂亮,哪个部分都是好的。
    iEggache
        5
    iEggache  
       2012-05-23 03:07:55 +08:00
    能用InterfaceBuilder的时候尽量用,别和自己过不去,而且手工敲效率低还容易产生各种bug....
    Elfe
        6
    Elfe  
    OP
       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
        7
    Elfe  
    OP
       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
        8
    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
        9
    Livid  
    MOD
    PRO
       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
        10
    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
        11
    Smartype  
       2012-05-23 08:24:38 +08:00
    @Livid 呵呵,当然"可以"。但是不好。
    对于使用代码还是xib,我个人认为和界面复杂度/标准度有关。
    试想,path会用xib?
    我如果要简单的支持ipad+iphone,我也会是直接写代码,重复工作少,便于维护
    damngood
        12
    damngood  
       2012-05-23 08:47:28 +08:00
    收藏, 刚好最近也在就项目思考这个问题
    以前也是所有的view层的构建都放在loadView/viewDidLoad这些方法里面, 看上去确实有OP提到的问题。
    现在也是倾向于单独创建一个XXView出来, 然后用tag来定位其中的子View, 这样的话Controller会看起来纯粹点。
    wtl
        13
    wtl  
       2012-05-23 09:19:26 +08:00
    @damngood 就我个人粗浅的理解,controller就是大杂烩,各种view都塞进去。

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

    当然,如果你自定义的view是可以到处重用的,那另说。 如果只是真对某个controller, 这样的分割,意义并不大。
    wtl
        14
    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
        15
    damngood  
       2012-05-23 10:34:44 +08:00
    @wtl 对, 可重用性也是考量因素之一

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

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

    IB有些属性没法设置,最奇怪的是竟然连 autoResizingMask也无法设置,这个可以设置的话,对于支持横屏竖屏可以省不少事(当然你可以说IBOutlet然后在.m中只设置这个属性)。
    lex
        17
    lex  
       2012-05-23 13:30:52 +08:00   1
    @Yonsm 是吗?我以为这个面板是设置 autoResizing 的。。
    Elfe
        18
    Elfe  
    OP
       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
        19
    Gal3rielol  
       2012-05-24 09:37:11 +08:00
    如果不使用nib,等同代码应该放在viewcontroller中的loadview:中。
    并且view hierarchy就是应该在view controller中构建并控制的,比如说想让一个界面元素隐藏,这个工作明显应该让vc来做。

    如果是刚接触这个平台,我推荐使用纯代码的方式构建界面,当对整个平台有一定的了解的时候再用interface builder.
    Elfe
        20
    Elfe  
    OP
       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 去啦
    Yonsm
        21
    Yonsm  
       2012-05-25 18:49:26 +08:00
    多谢@lex
    ,那现在就是有了啊。是以前老版本时候没有设置还是我没注意到?
    Yonsm
        22
    Yonsm  
       2012-05-25 18:55:29 +08:00
    @Elfe 我个人对MVC的理解是:Controller loadView 中是可以创建View的,除非一个View的代码足够复杂或者有特定的目的,否则永远不要去子类化View(说简单点,Controller就是搭积木,除非一个没有线程积木块符合你的要求,否则不要自己去制造积木块)。当然一个程序可能会有大量复杂的界面,所以子类化View是不可避免的(xib文件也可以认为是子类化View或者子类化Controller)。

    最后,实际上我习惯是在viewDidLoad中去创建sub view,viewDidUnload的时候去设置view相关的成员变量为nil,不知道是不是我的理解错误了。
    lldong
        23
    lldong  
       2012-05-25 19:08:52 +08:00
    最近RubyMotion的社在一DSL,teacup,可以利用似CSS的方式界面
    https://github.com/rubymotion/teacup
    edison0951
        24
    edison0951  
       2012-05-29 15:55:39 +08:00
    IB更多的适合静态元素,CONTROLLER比较适合动态元素
    MosquitoLiu
        25
    MosquitoLiu  
       2012-06-04 11:40:10 +08:00
    手工。能更好的控制内存。
    xatest
        26
    xatest  
       2012-06-04 12:22:10 +08:00
    为了兼容iOS 4所以用nib来做界面而不是Storyboard,做完才想到如果要改成只兼容iOS 5+的Storyboard,界面岂不是要全部重做一次?所以决定以后把界面用代码实现。
    xuming
        27
    xuming  
       2012-06-04 14:00:20 +08:00
    MVC不是圣经,没必要完全遵守,对于不是很复杂的界面,个人觉得用代码,比用nib要灵活的多。
    davidzhang
        28
    davidzhang  
       2013-05-28 16:41:41 +08:00
    你用哪个方便就用哪个喽,什么角色,我自己觉的她是扮演view的绝色哦
    Nobuta
        29
    Nobuta  
       2013-08-06 15:52:26 +08:00
    居然说用纯代码写效率更高?你用纯代码写个复杂点的设置页面,然后再用storyboard设计一个设置页面,然后你就知道storyboard的好了,我以前也喜欢手工码字,后来想想何必为难自己呢 ~~ 当然在一些需要灵活实现的地方肯定还是要纯敲代码的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2686 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 02:30 PVG 10:30 LAX 18:30 JFK 21:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86