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 · 10837 次点击
    这是一个创建于 4601 天前的主题,其中的信息可能已经有所发展或是发生改变。
    刚开始玩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
       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/domesticcatsoftware/DCIntrospect
    paloalto
        3
    paloalto  
       2012-05-23 01:35:45 +08:00
    刚接触StoryBoard,感觉对于我这种菜鸟还是挺方便的。
    Kai
        4
    Kai  
    MOD
       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
       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   ·   实用小工具   ·   4072 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:26 · PVG 13:26 · LAX 21:26 · JFK 00:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.