Google+ Badge

Tuesday, January 13, 2015

Why I have given up on Interface Builder and Story Boards

I just ran into another case where Interface Builder did not allow me to do what I wanted to do and I finally just gave up and pulled everything but the first view controller from the storyboard. This is the story of how I got to this point.

My first iOS app was one of "finish this". Another developer who was no longer with the company had developed the app. I had the job of finishing the app and converting it to Android. I already knew Java and had written an Android app that was in the store. The iOS version used NIBs as this was back in the iOS 4 timeframe.

I continued down the NIB path and converted the app to be universal with special code for iPad layouts. There was special cases for landscape vs. portrait on one of the screens as well. Seemed to work OK but it was a fairly straightforward app.

I worked only on Android apps for a some time before my next position where I did both iOS and Android work again.

The next iOS app I worked on was written by another developer and he used storyboards. Still using the old style layouts with pixel perfect positioning. I kept the storyboards in place seeing some of the advantages of using them and added the iPad storyboard side of things. I liked how much easier it was to get things going, used segues and like the idea of seeing the program flow in a visual designer. Took quite a bit of web research to understand how it all tied together and a lot of clicking on tabs in IB to find all the secret nooks and crannies where you could set things.

I did a couple of other apps for the company that I got to write from scratch. I used the new found storyboards for them as well. Sadly none of these apps went to market as they never finished the server side of the work. Lots of pretty apps to demo at sales meetings but they were just demos.

For my current job I am again getting to write the app from scratch. I am doing the same with the Android side of things. I started out using storyboards and it was time to get into autolayout. Since I have been doing Android work and I have also done a lot of Java desktop work I have a solid understanding of doing layouts that scale.

I dove into autolayout and found it rather confusing. It appears to me to be written in the land of academia instead of the land of real world programming. One layout to rule them all no matter how you have to force things into it. Very verbose in one code only format and very terse in the other. If you do it in Interface Builder then you just have to know how to do things. Click here, Ctrl + Click here, set up constraints, delete them, set them up again, have them conflict, pull hair. Always something wrong and it get really bad when you have a complex layout. For a company that prides itself in UI and UX I must say IB is not a good reflection of that goal.

After fighting it and working with other iOS devs over chat I found Masonry and switched to that. Yes, it is code and not WYSIWYG but I could create complex layouts and have them work. I could do different layouts for iPad and iPhone and follow them logically. I still have storyboard layouts but most of them were empty as the code created the real layout. I was just using them for segues and to see program flow. That was until yesterday.

There I was back in Interface Builder. I just wanted a UITableView to move down one level, to have another UIView as its parent. IB fought me tooth and nail. I could and a UIView to the list but it would not show up under the UIViewController no matter how I dragged and dropped and clicked. I then said screw it and deleted that entire view controller and created a new one where I could re-add the UITableView but then all my segue links broke and all the IBOutlets into the code broke and I would have to do it again for the iPad storyboard and all the work went on and on. Plus Xcode crashed more than once while I was in it doing simple things.

Storyboards end up sucking pretty quickly. There is not enough screen room to see your iPad layouts. You get to see one scene at a time. Sure you can zoom out but the minute you edit something it zooms back in. Just opening a storyboard seems to trigger Xcode into thinking there was a change. If you look in the XML you will see it changed x = 4.0 to x = 3.999999999 or something just as stupid. Everything I did I had to do twice, once for iPhone and once for iPad. The IDE does not tell you if you forget to wire up a UIView to an IBOutlet. Objective C does not care if you send messages to a nil object. Moving a UIView can screw up the whole layout quickly. You can't see all the constraints in one place, you have to look in each level of the layout to see them and they are terse and unrelated to each other. When you try to Ctrl+Drag a UIView into the code you hardly can see anything else on screen.

I gave up. IB was fighting me not helping me. I converted all the code to Masonry and I was able to control that layout exactly. I had to move all the segue processing in code as well. It took me all day to get my code back to where it was before but now I am in control of all of it.

I don't have to do things twice. iPad and iPhone both work from one code base. I may have some if statements in code to tweak layout for iPad but I don't have to double layout it out in a crappy UI editor called IB and I don't have to double connect every UIView to a IBOutlet.

I can move a control around in my layout by changing a few lines of code instead clicking a bunch of times in IB and having it get pissed and redo other constraints.

I can name my controls so when I do get log messages about my layout being screwy I know exactly which UILabel it is mad about instead of guessing.

Another issue that bit me, I fixed, that bit me again and I fixed the right way arose. I needed a second line for the title area on iPhone. iPad has enough horizontal space to not need this. I was using the navigation prompt property which adds a second line of text to the title area. On Android I could use title / subtitle to do same thing but on Android this requires no extra vertical space.

How did this bite me twice? A number of months ago I wanted to add a UILabel above my UITableView but I could not due to same issues that I just covered, I could not get the UITableView hosted by another UIView. Thus I used the prompt property. It worked OK. After the conversion away from storyboards everything in this UIViewController aligned just fine the first time I displayed it but when I tapped a table row and moved to the detail screen then back to the table screen setting the prompt caused the navigation area to grow and it covered up part of my table. Rotating to landscape and back would fix it. I tried all sorts of relayout, needs display, calculation of offsets etc. and could not get it to work. Why autolayout would not stay in sync is beyond me but I got sick of fighting that.

Then I remembered what I originally wanted to do - put a UILabel above the UITableView on iPhone only. Now I am in control as I am using Masonry. Put the UILabel in place and changed all code references from prompt = to promptLabel.text = and I have a working layout the way I originally wanted.

I have no plans use prompt again due to it screwing up layouts and I will not be using storyboards or Interface Builder either. They just are not stable and cause more trouble than they are worth. I also do most of my work in AppCode instead of Xcode as AppCode does a much better job in a lot of areas. Better editor, much better refactoring, GIT actually works properly and it is stable. I have had it crash on me once in the two plus years I have been using it.

The other added benefit - I can take my code and drop it in another project and it will work. I have no dependencies on copying the layouts twice and having to manually reconnect every single freaking UIView to an IBOutlet. My code is self contained. It lays itself out and knows how to talk to all of its controls.

Goodbye IB and storyboards. I don't miss you.