Working Without a Nib
Four score and minus seventy-two years ago, I brought forth on this internet a new blog post, conceived in levity, and dedicated to the proposition that no nibs are created. Since then, much has changed in the Mac world.
[…]
The problem is that you need to call
[myWindow setReleasedWhenClosed:NO]
. In pre-ARC code, this would not be surprising to old-school Cocoa coders. However, ARC does not even allow you to use the-release
and-autorelease
methods, so you might think that-setReleasedWhenClosed:
would not be allowed either, or would at least be ignored. And you would be very wrong.
My goal is to make all my projects nibless. Nib and xib files have caused me no end of problems. Even files that haven’t been edited in years spontaneously stop working when Xcode is updated and its xib compiler changes. (Most of the problems manifested on previous OS versions, where it was harder to detect them and to test fixes.) And that’s to say nothing of the advantages that doing interfaces with code offers. I’m convinced that with current technology (e.g. Auto Layout, Swift), using Interface Builder is a poor time investment for non-temporary projects. As Johnson writes:
Initial nib UI implementation is faster, but it’ll haunt you forever.
I’m leaning the same way about Core Data models, except that there seem to be places where the frameworks really want to have a model file saved to disk.
Update (2016-10-19): Steven Woolgar:
Especially with ibtool failing randomly all the damned time.
I take back everything nice I said about Interface Builder a few weeks ago on Under The Radar.
After introducing NSStackView there is no more excuse to build any UIs in IB.
Previously: How Much, or How Little, I Use Interface Builder These Days, Stopped Using NIBs Thanks to Auto Layout, Decoding Old Nibs: a Sad Tale of Vendor Lock-in and Abandonment.
Update (2016-10-20): John Stricker:
If you were to restrict yourself to using interface builder for this layout, there are many limitations:
- you couldn’t as easily preserve two different styles of the view
- you wouldn’t be able to use loops, constants and enums to lay out the view
- you wouldn’t be able to adjust the content, size and layouts of the buttons all at once.
Update (2016-10-21): Peter N Lewis:
I use xib’s for everything in Keyboard Maestro. And have special Lint code to detect inconsistencies. Coming to the conclusion I'm an idiot.
Update (2017-06-29): Jeff Johnson:
Many years ago I posted a sample nibless application on my old blog, but since then … much has changed. Given the renewed interest, I've decided to post a brand new sample application.
Update (2017-07-01): See also: iPhreaks Show.
Update (2019-03-07): Cédric Luthi links to all 11 parts of Johnson’s series (tweet).
Update (2020-04-23): Jeff Johnson:
So what happens is that NSApplication keeps a strong reference to all open windows in its ivar
_openWindows
if the app uses the 10.13 SDK or later, otherwise it doesn’t keep a strong reference, and you’re on your own. Note that the 10.13+ behavior can be overridden by setting the NSUserDefaultNSApplicationStronglyReferencesOpenWindows
to false, which gives you the 10.12- behavior again.[…]
The good news, however, is that if your app does have a deployment target of 10.13 or higher, then the memory management of
NSWindow
becomes relatively simple. It’s almost “magical” again, and we didn’t needNSWindowController
.
10 Comments RSS · Twitter
"with current technology (e.g. Auto Layout, Swift)"
Auto-layout is a nightmare to use (both in Interface Builder and code). It was supposed to be:
- easier
- more powerful
- faster
The sad reality is that:
- it's so easy to use that being able to understand how this is supposed to work in either Interface Builder or code is far more difficult than the old strings and struts method. And when you thing you have finally understood how it works, there's always a new case that makes you question your understanding of the whole thing.
- sure it can let you do more stuff without code. But you can spend hours figuring out how to do simple things you could do with the old strings and struts method in seconds (either in IB or with the autoresizing mask code). And once you've discovered that the entire auto-layout thing is a lie and that you still have to use invisible group views to be able to do some stuff (because only the latest versions of OS X provides the required objects to avoid this), the walls are going to be covered with headprints.
- auto-layout is so slow that it's unusable in tableviews. auto-layout is so slow that when you have a NSTextView, resizing a window is just a nightmare. And it's sure faster to break.
Auto-layout is so bad that here's a caricatural history of Auto-layout through WWDC sessions:
- Year 0: Auto-layout is awesome and, please, look how awesome it is that you can write your layout constraints in code with - | strings.
- Year 1: Auto-layout UI in IB was so awesome that people were mostly writing their constraints in code. So we improved the UI.
- Year 2: Auto-layout UI in IB was so awesome that people were mostly writing their constraints in code. So we improved the UI.
- Year 3: Auto-layout code is so awesome that people decided to write better code wrappers for it.
- Year 4: Auto-layout was so that powerful so we decided to add new vertical and horizontal references to make simple things easier to do.
- 2016: Auto-layout is so powerful that we recommend that you keep using strings and struts/autoresizing masks when possible and only use Auto-layout if you need to. (OK, this one is not caricatural, that is exactly what they say at WWDC this year).
And what is Swift supposed to bring to the equation considering that Swift was also supposed to be easier, more powerful and faster but also is a marketing lie for the first and last features and the powerful feature is killed by the fact that using the AppKit framework in Swift is as bad/boring/annoying/displeasing as using the bridging APIs when using ARC and CoreFoundation in an Obj-C project? Of course, if you're writing your project in Swift, you don't have the choice but it doesn't make it any better to code the UI.
The only good thing about writing the UI in code is that it's way better when using SCMs. Writing the UI in code can also be understood if you're just implementing a UI based on very detailed specs.
But if the UI design of the app is still a work in progress, do you really enjoy having to endure the entire Xcode build time* to get a glimpse at any small change you made to the UI?
Yes, there are some well-known issues with xib, nib:
- not being able to edit a xib file in Xcode x.y because Xcode x+1.1 decided to automatically update your xibs without your consent as soon as you selected them in the Project Navigator (this is such a stupid feature).
- having to edit all the localized xib/nib files when you add a button for instance if you're not using the Base.lproj solution. But honestly, I have never had a problem with this and I find this provides way better UI results for localizations. Otherwise, you end up with too many tradeoffs for languages that are not English (replace English your development language if needed).
- the inability for Apple to provide widgets in IB the day they are introduced in the AppKit. So yes, you have to write code.
- backward compatibilities warnings in Interface Builder because it decided to turn on some options by default before you decreased the targeted OS version.
- early bugs in Interface Builder (like the one related to the background of cells in Mac OS X 10.0,10.1 and 10.2 that you had to fix it in the awakeFromNib methods of your controllers).
- very poor UI to set auto-layout constraints: just don't use auto-layout.
and very rare issues with broken xib/file: like having a flag for a NSWindow being corrupted and this only shows up when running the app but not when editing the window in IB.
But I would not move to coding the entire UI in code, this is so barbaric, time consuming and not visual. I don't care having to write some complex alignment stuff in code by computing the frames and setting them from time to time. It's very rare I have to do it and the maths involved are way easier than trying to figure out how to express this in auto-layout constraints.
Did I mention I dislike auto-layout and entire UI in code? Yet I can appreciate the challenge/hack when there are no xib/nib files at all.
* and if your UI is inside a plugin, you also need to copy the new binary and load the master .app before being able to see the changes. Sigh.
Wow, I miss the old Interface Builder because I'm a hobbyist who doesn't have time to learn the new layout stuff. It hadn't occurred to me that the new stuff was that much worse. In the old days, Cocoa noobs who tried to do UI in code were mocked and ridiculed, since that was not the Cocoa way: you used nibs, and they saved time and were easy to maintain. It's a damn shame if Apple has ruined that, too.
And to think iOS devs (myself included) made fun of Android devs (like myself) when writing “xml” for Layouts.
I’ve always preferred the Android approach. Understand the XML behind the scenes (you will need it for SCM/Easy inspection/Change/Future), then build a UI Tool. The last step is hard (as can be seen by looking at the somewhat sad state of Android Studio UI editor). The new UI editor is slow, inaccurate and can break your perfectly working ConstraintLayout, but it’s getting better. The good news is, nobody really cares much, Android devs still consider learning XML/Layouts part of the learning process of Android / Android SDK.
When I touched IB for the first time a few years ago, I was shocked to see how hard to read it was and how “don’t touch it by hand” other devs were about it.
I agree that IB is better than Android Studio visual editor at this time, but I also agree that IB is horrible and nib/xibs are even worse. Oh well, we can’t live in a perfect world. Never did Windows Phone development, I wonder what that C#/Net framework was using…
Quite late to this, but Winphone devs used Visual Studio + XAML. Conceptually similar to Android, but easier and better organized.