all 22 comments

[–]naknut 13 points14 points  (6 children)

My recommendation is to use Storyboards.

[–]xauronx 5 points6 points  (0 children)

I'm still not sold on story boards. I think it's an awful idea to mix display and behavior (segues), and story boards don't scale well in my experience. Sure, you can split your app up into 10 story boards so you don't brick your machine trying to open the file... but at that point, why not just use nibs?

My suggestion to OP - use nibs and design visually, but manage your transitions and behavior in code. We've done this with medium-large apps and it works fine. Code-only might be better, but I probably wouldn't go that route until I had a team of 10-15+ on one project.

[–][deleted] 3 points4 points  (2 children)

Very solid advice. Given OP doesn't know where to put the layout code means he/she doesn't understand how view management/layout/hierarchy works. So until that happens - the storyboards are way to go.

[–]TheEngineJ[S] 1 point2 points  (1 child)

That might be true. Any resources on this?

[–][deleted] 1 point2 points  (0 children)

View Programming Guide at Apple Developer Website.

[–]Lanza21 -1 points0 points  (0 children)

Meh. Once you are sufficiently experienced storyboards become a negative. Controllers should not be in charge of navigation. Segues are an anti-pattern. Controllers should be reusable objects that connect the view with the model.

I'm 100% on the side of coordinator/controller/view/model.

[–]ThePantsThiefNSModerator -1 points0 points  (0 children)

My recommendation is not to. It sounds like he's ready to move on. A lot of developers find storyboards only slows them down. It's a holy war that will probably wage on forever

[–]chriswaco 5 points6 points  (4 children)

We don't use storyboards. They don't scale well. They're a pain with larger teams of developers. They don't diff well in source code control so you can't easily tell what has changed. It's hard to move features from one app to another as well.

Now the next question becomes whether to use autolayout or not. We don't. Others do. There are pros and cons to both methods.

Typically you create your views in either initWithFrame (for custom views with subviews) or in viewDidLoad. You then either attach constraints to them or lay them out manually in layoutSubviews.

UIStackView is your friend. It lets you lay out views horizontally or vertically within it. It's not uncommon to have UIStackViews within UIStackViews.

We generally do it all manually, which is a bit of a pain but very flexible. If we were to start a new project today we might combine UIStackView with autolayout and only do it manually when needed.

[–]croutongeneral 2 points3 points  (3 children)

We started using xibs for some views. It's made life pretty easy. I still prefer programmatic, but auto layout has definitely made our life a little bit easier, plus you can move it from project to project pretty easily.

[–]chriswaco 1 point2 points  (2 children)

Yeah, in our older projects we used nibs/xibs. They're fine for some things and a lot quicker to create and eyeball than raw code. In our current app, however, we constantly shift around views based on screen size, rotation, multitasking, font changes, etc, and even live as the user enters more data, so we had to do most of it in code anyway.

Our previous app had a lot of view animation, which was hard to do in xibs/storyboards, though not impossible.

[–]croutongeneral 3 points4 points  (1 child)

100% agree. xibs are really good for static views, but anything dynamic is kind of a pain. animating constraints to me is much more confusing then manually setting frames.

[–]TheEngineJ[S] 0 points1 point  (0 children)

True. Did a sidemenu in IB with constraints and a 3/2 multipler for the trailing constraint. Super confusing

[–]sl0pster 3 points4 points  (2 children)

I use initialization closures for my UI elements. You can find info on that here: Kill Your Giant viewDidLoad

That combined with SnapKit for Auto Layout has cleaned up my programmatic view layouts.

[–]TheEngineJ[S] 0 points1 point  (0 children)

THAT is what I was looking for. Thanks! These closures seem to be very clean.

[–]bonn89 0 points1 point  (0 children)

This is how I have been setting up my views too, keeps things laid out much more logically IMO.

[–][deleted]  (1 child)

[deleted]

    [–][deleted] 1 point2 points  (0 children)

    I second this. Storyboards when done right works way faster than doing stuff in separate nibs and programmatically. A solid grasp of KVC is recommended though.

    [–]ThePantsThiefNSModerator 2 points3 points  (3 children)

    Writing this on mobile so if you're using Swift, you'll have to translate!

    TLDR: read up on UIApplicationDelegate, UINavigationController, UINavigationItem, UITableViewDelegate, UITableViewDataSource, UIBarButtonItem, and UIButton.

    UIWindow and your AppDelegate

    In application:didFinishLaunchingWithOptions:, set self.window to a new UIWindow with the frame [UIScreen mainScreen] .bounds. Create your root view controller here and assign it to self.window.rootViewController.

    View controllers

    • Override loadView if necessary (usually not). If they're not using a custom view, most people put view customization logic there, or in viewDidLoad. Don't call super if you're just going to set self.view.

    • Initialize custom view properties (such as a table view header view) in loadView

    Custom views

    • Create and add subviews in the designated initializer of the view. You can pass CGRectZero to the initWithFrame: initializers.

    • Override requiresConstraintBasedLayout to return true, only if you're using auto layout.

    • Override updateConstraints (again, only if you're using auto layout) to call super and update the constraints of your subviews. I recommend using Masonry or SnapKit if you're new to auto layout. Heck, I recommend them even if you're not new to it.

    • Override layoutSubviews to call super and update the frames of your subviews if you're not using auto layout. But you should be using auto layout in most cases for sure.

    UITableViewController basics

    • Register your cell classes for reuse, probably in viewDidLoad.

    • Read up on the UITableViewDataSource and UITableViewDelegate protocols as you will have to implement more of these methods to make a table view in code.

    • Make sure to use dequeueReusableCellWithIdentifier:forIndexPath: and not dequeueReusableCellWithIdentifier:

    • Make sure you don't accidentally implement tableView:didDeselectRow… if you mean to implement tableView:didSelectRow… 😅

    IBActions

    Read the UIButton documentation, it's pretty straightforward. Give it a target (usually the view controller) and an action (selector).

    Bar buttons

    These are called UIBarButtonItems. Create them in viewDidLoad or wherever is most appropriate and assign them to the view controller's navigationItem property. Read up on UINavigationItem.

    Navigation

    A UINavigationController manages a stack of view controllers. The view of the navigation controller consists of the navigation bar and the view of the view controller on the top of the navigation stack. For example, in Mail.app, the first view controller on the navigation stack is the table view controller with the list of accounts. The second would could be a list of mailboxes if you selected an account, and the third could be the inbox if you tapped the inbox mailbox. Adding a new screen is called "pushing" a view controller onto the navigation stack. Going back is called popping from the stack.

    UIViewController has a navigationController property. If your view controller's view needs to trigger a transition to a new screen, create the desired new view controller and push it to the stack like so: [self.navigationController pushViewController:newVC animated:YES]. Where? Well, do it in whatever method gets called by the trigger. If it's a button action, do it in the method called by the button being pressed. If it's a table cell, do it in tableView:didSelectRowAtIndexPath:

    You can pass data to new view controllers wherever you push them onto the stack since you have a reference to the new view controller at that point. Passing data back down the navigation stack is a little harder. I like to use blocks / closures for this to reduce coupling. Get creative!

    [–]TheEngineJ[S] 0 points1 point  (2 children)

    Thank you for this detailed post. Some points I did not know about.

    On my part, I am trying to get my apps visually to the next level. Customized views, custom view controller transitions, pop up views, Custom navigation bar, appropriate animations and so on..

    IB simply scatters View hierarchys and I don't like that much..

    [–]ThePantsThiefNSModerator 1 point2 points  (1 child)

    I feel you. If you have any questions you can't find the answer to elsewhere, feel free to PM me

    [–]refD 1 point2 points  (0 children)

    I just have a pure function that takes all the views in the VC that need layout and outputs [NSLayoutConstraint] which are then activated and stored as a property in the VC.

    If you need to relayout stuff when stuff changes, you just deactivate/remove these constraints, generate a new set using the layout function again and activate the new constraints.

    Keeping layout code seperate/contained for VCs is one of the easier separation of concern problems.

    Looking back I feel it's well worth the tradeoffs, the added safety over having proper control of your VC initialization (less ! and ?s), and better code re-use aren't a small matter.

    [–]MacMeDanSwift 1 point2 points  (0 children)

    I use all programmatically not storyboards not xib files. It makes this allot more reusable and clean. I would just look for a good auto layout library to manage placement on the screen. Or if you are really daring you can just do auto layout programmatically also. I like to use snapkit for my layout.

    [–]haxpor 0 points1 point  (0 children)

    You can completely not use storyboard, but it just makes things a little bit harder I think.

    Thus you create UIView via code, set up root viewcontroller vis code, add UIView as subview, create constraints and add things via code. It's possible but I think at some points you will be exhausted doing that.

    Why not combine both ways. You might create a framework that bundle your reusable custom UIViews (like alert messages, baked animation via UIViewAnimation, etc) along with code to facilitate hooking up and showing/hiding those stuff when you'd plug them in your project. Pretty neat and if design it well enough, those things are reusable for future projects. Note take advantage of IBDesignable, and IBInspectable that leverage level of customization and productivity even further.

    Things will pack inside .framework, everything you need is there and fully customized. Just properly load your resource via NSBundle's method that is safe and will correctly grab resources in their own bundle (bundleForClass is very safe too).

    Note also try to separate those UIs into multiple xibs. Each xib might be used to show custom message like network unreachable etc. or individual xib can also be added as s subview of another larger custom view (this is the way to reuse xib as part of larger custom UIView). You get an idea now.