Skip to content

Instantly share code, notes, and snippets.

@rbobbins
Created June 12, 2015 21:13
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rbobbins/236b2160ab9621f3f8e7 to your computer and use it in GitHub Desktop.
Save rbobbins/236b2160ab9621f3f8e7 to your computer and use it in GitHub Desktop.
Cocoa Touch Best Practices

Cocoa Touch Best Practices

Speaker: Luke Hiesterman, UIKit Engineer

Agenda

  • App lifecycle
  • Views and view controllers
  • Auto layout
  • Table and collection views

Goals

  • Peak performance for your app
  • Top-notch, polished user experience for your app
  • Futue-proof the code in your app, to minimize work as new versions of iOS come out

App Lifecycle

  • Launch quickly when the app first lanches
    • That's how you make your app appear quick, performant
    • How to: return quikcly from applicationDidFinishLaunching:
      • Do this by deferring long running work
      • Users will kill your app if it's too slow, because they think it's unreponsinve
  • Be responsive to every input
    • Not just about asynchrony
    • Move long running work to background queues
      • This can be applied any time in your app, not just at launch
      • Once work is done, perform UI updates on the main queue
  • Launch quickly when the app is opened again
    • If your app is using a lot of memory when it's in the background, it's the first one to get killed
    • When your app is background-ed, get rid of unused resources/memory.
  • Leverage apple's frameworks
    • Reduces maintenance burden. I.e, use UINavigationController instead of rolling your own
    • You get improvements for free
    • You're able to focus time on whatever makes your app special
  • Properly manage version change
    • Target the 2 most recent major releases (i.e iOS 8 and 9, as of this fall)
    • Include version fallbacks.
    • DO NOT DO THIS: if systemVersion == 9.0
    • DO THIS INSTEAD: if systemVersion >= 9.0 (this is future proofing?! meh.)
    • OR DO THIS: #available(iOS 9.0, *) {} (new in swift.)
    • have an else clause

Views and view controllers

  • Layout on modern devices: layout to proportions
    • Avoid hard-coded layout values
    • Either (or both!) dimissions may scale
    • ex: Instead of thinking of a view containing a label that's 260 pixels wide with 30, think of it as a view that contains a centered label
  • Don't think about things in terms of portrait/landscape
    • Think about them interms of size classes instead
    • Make your designers think about it in terms of size classes also.
    • Packaged in UITraitCollection
  • Use properties, not tags
    • If you need a reference to a subview, save it as a property (instead of refefrring it to by tag)
    • Avoid setTag: and viewWithTag:
      • Possible collisions with other code
      • No compiler warnings
      • No runtime errors - best case is a crash
    • Instead, use instance variables and properties
  • Make timing deterministic
    • Don't "guess" how long an animation will take.
    • Leverage UIViewControllerTransitionCoordinator
      • Animate alongisde a transition
      • Get accurate completion timing
      • Supports interactive and cancellable animations (!)

Auto Layout

  • Modify constraints efficiently
    • Identify constraints that get changed, add or removed.
    • Unchanged constraints are optimized
    • Avoid removing all constraints. (Removing all constraitns is worst practice, the opposite of best practice)
    • Use explict constraint references (via properties)
      • Same as the advice about tags.
  • Don't add duplicate constraints.
    • Duplicates are implied by existing cosntraints
    • Can cause excess work for the layout engine
  • Create flexible constraints
    • Avoid hard-code values (eg: V:-30-[label(260)]) is bad.
      • Missed the good counter-example
  • Fully specify constraints
    • Underspecified constraints generate ambiguiity
    • Ambiguity can cause undefined, non-deterministc behaviro
  • Testing and debugging:
    • -[UIView.hasAmbiguousLayout] - tells whether a view has ambigusous layout. Can also be called on UIWindow to get results for the entire view tree
    • -[UIView _autolayoutTrace]
    • Put both these methods in your unit tests. Test whether a view has ambivuous layout. If it does, run the _autolayoutTrace method to include the layout in your logs

Table and Collection Views

  • Use self-sizing cells. (Introduced in iOS 8)
    • Fully specify the constraints for your cell
      • Think about it as a machine that has width as its input and returns height as its output
      • If it's not working, try setting a constraint on the height of your content view. You can use this as a debugging tactic - if it fixes your problem, your constriants are wrong
  • Animating tableview cell height changes
    • Don't call reload data. Looks jenkity.
    • You want nearby cells to also animate their position changes
    • You don't need to call reloadCellsAtIndexPaths - you can just change the content directly.
     tableview.beginUpdates
     Update model
     Update cell contents
     tableView.endUpdates
    
  • Fast collection view layout invalidation
    • Modify only what is needed
      1. Invalidate on bounds change
      2. Build targeted invalidation context
      3. Repeate as ncessary
    • This is a fast technique. (This is what the iPhone photos app uses for its sticky header)
@narner
Copy link

narner commented Jun 29, 2015

This is super helpful, thanks for sharing this! By any chance, did Luke provide any examples of using Unit Tests to check for layout ambiguities? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment