简体   繁体   English

用笔尖或代码设计iPhone界面?

[英]Designing the iPhone interface in a nib or in code?

I've been pondering over this question for a while now... 我一直在思考这个问题一段时间了......

On the one hand, Interface Builder offers a really easy way to design the interface and wire the elements up with objects in code. 一方面,Interface Builder提供了一种非常简单的方法来设计界面,并将元素与代码中的对象连接起来。

On the other hand, in larger projects, Interface Builder becomes a hassle to maintain. 另一方面,在较大的项目中,Interface Builder变得很难维护。

Any suggestions would be greatly appreciated. 任何建议将不胜感激。

I was once very strongly against using Interface Builder in my own projects. 我曾经非常反对在我自己的项目中使用Interface Builder。 This was due to a number of factors. 这是由于许多因素造成的。 I started first working with the Xcode tools when the iPhone SDK was back in beta (around March 2008), and since I didn't come from a Mac Cocoa background I was somewhat unfamiliar with using it. 当iPhone SDK重新开始测试时(2008年3月左右),我开始使用Xcode工具,因为我不是来自Mac Cocoa背景,所以我对使用它有点不熟悉。 This was not the major factor in my initial rejection of IB for iPhone development, though - Interface Builder for iPhone development during the initial iPhone SDK beta did actually suck and it was a pain to use. 这不是我最初拒绝用于iPhone开发的IB的主要因素,但在最初的iPhone SDK beta期间,用于iPhone开发的Interface Builder确实很糟糕,并且使用起来很痛苦。

However, the story is much different with today's iPhone SDK. 然而,这个故事与今天的iPhone SDK有很大不同。 While there are still certainly some annoying IB bugs, I've done a nearly complete 180˚ with my attitude toward using Interface Builder. 虽然仍然有一些恼人的IB错误,但我对使用Interface Builder的态度已经接近完成了180˚。 More often than not it is a good idea to use Interface Builder in your projects, I've found. 我发现,在你的项目中使用Interface Builder通常是个好主意。 It is a great tool now, and you should avail yourself of it. 它现在是一个很棒的工具,你应该利用它。

Now, don't get me wrong - I am still firmly in the camp that believes that you should be able to implement anything you do in Interface Builder using code alone and I think being able to do so is invaluable. 现在,不要误解我的意思 - 我仍然坚定地认为你应该只使用代码来实现你在Interface Builder中所做的任何事情 ,我认为能够这样做是非常宝贵的。 Do not use Interface Builder as a crutch - you'll only hurt yourself (and your productivity or the quality of your products) in the end. 不要将Interface Builder用作拐杖 - 最终你只会伤害自己(以及你的生产力或产品质量)。 While the drag-and-drop niceties of IB are great for 90% of what you'll need to do, when you have something custom to implement that can only be done in code, you'll either wish you had followed or be thankful for following this advice. 虽然IB的拖放效果非常适合您需要做的90%,但是当您有自定义实现的东西只能在代码中完成时,您可能希望您遵循或感谢遵循这个建议。 I was lucky enough to hate IB long enough that I taught myself how to do everything in code alone, and then applied that knowledge back to IB. 我很幸运地厌倦了IB足够长的时间,我自学了如何单独用代码完成所有工作,然后将这些知识应用到IB。

Edit: 编辑:
To address the lack of reusability (perceived or real) with NIBs versus code...you won't be implementing something that is meant to be heavily reused in Interface Builder in all likelihood. 为了解决NIB与代码相比缺乏可重用性(感知或真实)......您将无法实现在Interface Builder中大量重用的东西。 You can't really make a custom control or view in IB, so that's ruled out, and in most cases you're going to be implementing a view controller subclass that is built to address a specific purpose. 您无法在IB中真正进行自定义控件或视图,因此排除了这种情况,并且在大多数情况下,您将实现为满足特定目的而构建的视图控制器子类。 You should of course always strive to make your code and associated resources as reusable as possible. 当然,您应该始终努力使您的代码和相关资源尽可能可重用。 This could include design considerations to ensure that you don't unnecessarily duplicate view controller subclasses that are very similar. 这可能包括设计注意事项,以确保您不会不必要地复制非常相似的视图控制器子类。

Using builders frees you of code that you would otherwise need to maintain and the less you need to maintain the better. 使用构建器可以释放您需要维护的代码,并且您需要的维护越少越好。

The layouts built by IB do require some maintenance but it is a standard tool with its own documentation and its own online support (forums, lists, etc). IB构建的布局确实需要一些维护,但它是一个标准工具,有自己的文档和自己的在线支持(论坛,列表等)。 If someone else ever needs to jump into your code, you can virtually guarantee they have experience with IB, but not necessarily your particular style of layout building. 如果其他人需要跳转到您的代码,您几乎可以保证他们有IB的经验,但不一定是您的特定布局构建方式。

It depends on your preference. 这取决于您的偏好。

I prefer to write it in code. 我更喜欢用代码编写它。

  1. I get to reuse the code. 我重用代码。
  2. Using a XIB/NIB generally breaks the one definition rule (if you are doing any customization). 使用XIB / NIB通常会破坏一个定义规则(如果您正在进行任何自定义)。
  3. XIB/NIB maintenance is often more tedious and error prone (ODR). XIB / NIB维护通常更加繁琐且容易出错(ODR)。 I really dislike maintaining button styles (example) for each button. 我真的不喜欢为每个按钮维护按钮样式(示例)。
  4. circular references are more likely. 循环引用更有可能。
  5. Code/objects/ib instances are often less reusable/modular. 代码/对象/ ib实例通常较少可重用/模块化。 Though I am the type to avoid a ui object that can do everything. 虽然我是避免可以做任何事情的ui对象的类型。
  6. Deferred/ambiguous initialization order makes for a pretty scary state for clients, which they must never assume an object is ready for use or entirely initialized (unless you prefer to maintain those checks, which is a good way to waste time). 延迟/模糊的初始化顺序使客户端处于非常可怕的状态,他们绝不能假定对象已准备好使用或完全初始化(除非您更愿意维护这些检查,这是浪费时间的好方法)。
  7. If performance is important, guess which is faster? 如果性能很重要,猜哪个更快?
  8. Resource management vs linker... seriously, I have written sub-programs and tests to verify nibs' existence in the bundle. 资源管理与链接器......说真的,我已经编写了子程序和测试来验证nibs在bundle中的存在。

IB is great for prototyping and browsing object capabilities and appearances (I am not a graphic designer), though I think it is easiest to just write it in code once the prototype exists if you have any intention of maintaining or reusing it. IB非常适合原型设计和浏览对象功能和外观(我不是平面设计师),尽管如果您有任何维护或重用的意图, 认为只要原型存在就可以在代码中编写它。

My recommendation: Write highly reusable and stable code libraries, and use IB primarily for prototyping and one-offs. 我的建议:编写高度可重用且稳定的代码库,并将IB主要用于原型设计和一次性。


Responses: 对策:

Sbrocket: I'm curious as to why you assert that circular references are more likely to occur as a result of using NIBs. Sbrocket:我很好奇为什么你断言循环引用更有可能因使用NIB而发生。

Hi Sbrocket: I'll start by saying I've used Interface Builder since the Project Builder days (Xcode's predecessor). 您好Sbrocket:我首先要说的是自从项目构建器开始以来我已经使用了Interface Builder(Xcode的前身)。

Lack of reliable structured ownership, identity, and initialization. 缺乏可靠的结构化所有权,身份和初始化。 I don't want ivars to be IB connections because it makes many classes difficult to use beyond 'the current context', In other words, it ties the code to the resource (more often than ideally). 我不希望 ivars成为IB连接,因为它使许多类难以在“当前上下文”之外使用,换句话说,它将代码与资源联系起来(通常比理想情况更多)。 Since you can't define initialization order or define initializers or additional initialization arguments in IB, you must then make the objects know about each other, creating circular dependencies and references. 由于您无法在IB中定义初始化顺序或定义初始化程序或其他初始化参数,因此必须使对象彼此了解,从而创建循环依赖项和引用。

Sbrocket: or why lazy initialization (assuming that's in fact what you're referring to) is so scary when its relatively easy (or in fact automatic in many cases) to ensure that the object is initialized and connected. Sbrocket:或者为什么延迟初始化(假设实际上你指的是什么)在相对容易(或实际上在许多情况下是自动的)确保对象被初始化和连接时是如此可怕。

Re: scary I was not talking about lazy initialization. Re:可怕我不是在谈论延迟初始化。 I was talking about deferred and ambiguous initialization order. 我在谈论延迟和模糊的初始化顺序。

Nib initialization is semi-ordered. Nib初始化是半有序的。 The actual order/process may vary, and this cannot be used reliably within reusable introspective programs... again, you'd end up writing too much code which is fragile, impossible to reuse, can never be assured to behave predictably, and must always validate state (yet another entry for circular dependence). 实际的订单/流程可能会有所不同,这在可重复使用的内省程序中无法可靠地使用...再次,您最终会编写太多易碎,无法重复使用的代码,永远无法确保其行为可预测,并且必须总是验证状态(循环依赖的另一个条目)。 If it is not a one-off implementation, why bother with the complications? 如果它不是一次性实施,为什么要烦恼并发症呢?

This approach to programming is chaotic and the implementations must (in turn) be prepared to handle anything at anytime. 这种编程方法是混乱的,实现必须(反过来)准备随时处理任何事情。 It is one thing to guard yourself from crashes, but to write defensive, production level code in this context... no way. 保护自己免受崩溃是一回事,但是在这种情况下编写防御性的生产级代码......没办法。

It is far easier to write a consistent program which initialization determines the validity in context, which the implementations can then know (if initialized) that the object is generally prepared to be used. 编写一致的程序要容易得多,初始化程序确定了上下文中的有效性,然后实现可以知道(如果已初始化)该对象通常准备使用。 Special-case complexity is minimized. 特殊情况的复杂性最小化。 Many such designs fall apart as program complexity increases, while library writers add layers upon layers of 'protective measures' just to keep gears moving - threading is a great entry for such heisenbugs. 许多这样的设计随着程序复杂性的增加而分崩离析,而图书馆编写者为了保持齿轮移动而在“保护措施”层上增加了层次 - 线程是这种heisenbugs的一个很好的入口。 Unnecessary ambiguities are unwelcome in reusable production level code; 不可取的歧义在可重复使用的生产级代码中是不受欢迎的; humans shouldn't have to cross reference all of a program's special cases, and the complexities concerning defined behavior and special cases only spread or are ignored (assuming they are properly tracked and documented, which is more combined effort than writing it properly from the start). 人类不应该交叉参考程序的所有特殊情况,并且有关定义的行为和特殊情况的复杂性只会被传播或被忽略(假设它们被正确地跟踪和记录,这比从一开始就正确编写它更加结合工作)。 I think we can all agree that onerous interfaces and implementations should be avoided. 我想我们都同意应该避免使用繁重的接口和实现。

Sbrocket: I'd also be interested to see some hard numbers that show that NIB loading is slower - of course, it would seem to make sense at first thought, but we're always such bad predictors of performance bottlenecks without some hard testing. Sbrocket:我也有兴趣看到一些硬数据显示NIB加载速度较慢 - 当然,它看起来似乎有意义,但我们总是如此糟糕的预测性能瓶颈没有一些硬性测试。

I never said (explicitly) that it was slower :) 我从未(明确地)说它慢了:)

Ok, in seriousness, NIB unarchiving was (for me) a surprisingly slow process, though our ideas of slow and unarchiving times can vary dramatically. 好吧,严肃地说,NIB unarchiving(对我来说)是一个非常缓慢的过程,尽管我们对缓慢和非归档时代的想法可能会有很大的不同。

Example: I had a document based app, and the nib loading was several times slower than the document loading, when document sizes were several times the nib size. 示例:我有一个基于文档的应用程序,当文档大小是笔尖大小的几倍时,笔尖加载比文档加载慢几倍。 Moving the implementation to code made the process much faster. 将实现移动到代码使得该过程更快。 Once it was on code and I had control of initialization order, I removed multiple multithreading complexities (checkpoints, locks, race condition entries, etc), which made document loading even faster. 一旦它出现在代码上并且我控制了初始化顺序,我就删除了多个多线程复杂性(检查点,锁定,竞争条件条目等),这使得文档加载速度更快。

Now that you have an explicit answer, I'll remind you that you have all the tools you need to measure performance. 既然您有明确的答案,我会提醒您,您拥有衡量绩效所需的所有工具。

Remember that performance analysis and enhancements are learned . 请记住, 学习了性能分析和增强功能。

Interface builder is great for a certain level of complexity. 界面构建器非常适合某种程度的复杂性。 For things more or less complex, I would rather do it in code. 对于或多或少复杂的事情,我宁愿在代码中这样做。

If you have an interface that will not be used in more than one way, has several but not lots of elements, and does not need any tricky layout, than IB is great. 如果你有一个不会以多种方式使用的界面,有几个但不是很多元素,并且不需要任何棘手的布局,那么IB很棒。

In the long run, I almost never use IB. 从长远来看,我几乎从不使用IB。 That is as much the nature of the projects I work on as personal preference. 这与我作为个人偏好的项目的性质一样多。 There are definitely some interfaces that I would head straight to IB for, but I have not needed to create one of those in a while. 肯定有一些接口可以直接用于IB,但我不需要在一段时间内创建其中的一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM