#116: Instructions πŸŽ“


Teaching users how to use our apps is incredibly important. We should strive to do this through familiar UI patterns, intuitive flows, good error handling, etc. Sometimes though, we just need to explain what's going on.

Today we'll look at a fantastic new project from FrΓ©dΓ©ric Maquin called Instructions that can help us do just that. It's a library for easily adding "coach marks" to our apps. Let's dive in.

We'll start by adding a new CoachMarksController property to our view controller, and setting it as the data source for it:

let coachMarksController = CoachMarksController()

override func viewDidLoad() {
  coachMarksController.datasource = self

Next, we'll extend our view controller so it conforms to the CoachMarksControllerDataSource protocol. Instructions is highly customizable. It has support for custom body and arrow views, positions, highlights, and more. Let's keep things simple here and add a regular coach mark for a button in our app.

func numberOfCoachMarksForCoachMarksController(coachMarksController: CoachMarksController) -> Int {
  return 1

func coachMarksController(coachMarksController: CoachMarksController, coachMarksForIndex index: Int) -> CoachMark {
  return coachMarksController.coachMarkForView(launchButton)

func coachMarksController(coachMarksController: CoachMarksController, coachMarkViewsForIndex index: Int, coachMark: CoachMark) -> (bodyView: CoachMarkBodyView, arrowView: CoachMarkArrowView?) {
  let coachViews = coachMarksController.defaultCoachViewsWithArrow(true, arrowOrientation: coachMark.arrowOrientation)

  coachViews.bodyView.hintLabel.text = "This button launches the spaceship, proceed with caution!"
  coachViews.bodyView.nextLabel.text = "Got it"

  return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)

It's good practice to let users who don't need our coach marks skip them. Instructions has us covered. We can setup a "skip view" on our controller. We'll use the default one, which shows in the nav bar:

let skipView = CoachMarkSkipDefaultView()
skipView.setTitle("Skip", forState: .Normal)
coachMarksController.skipView = skipView

Finally we'll start the whole flow in viewDidAppear:

override func viewDidAppear(animated: Bool) {

Success! When we launch our app, the coach marks are now shown:

More info about Instructions can be found at