Weekly Sponsor: Zendesk ๐Ÿ’ก

We're welcoming back one of our favorite sponsors this week, it's Zendesk!

None of us have ever built a flawless app.

Chances are, no matter how good we think our app's user experience is, there's probably something users will need help with while they're in our app.

Yet in many apps, getting help is reduced to a "contact us" button that launches an compose email screen, or a just drops the user on a web page.

By forcing folks out of the app to get help, small problems can turn into big annoyances, and those will almost certainly turn into negative App Store reviews and poor ratings.

With Zendesk's Mobile SDKs, we can join the makers of Angry Birds, Venmo and Swiftkey in bringing native, in-app support functionality to our apps quickly and easily.

Our users can view help and support content, and even submit tickets to support without ever leaving our app. Neat!

Tickets go into Zendesk and can include technical details about the user and their device, history with our apps, and more.

Best of all, it's included with Zendesk at no extra charge.

We can use Zendesk's "out-of-the-box" iOS UI components to get up and running quickly, or we can build your own UI with SDK API Providers.

A huge thanks to Zendesk for sponsoring!

Topics

#294: Annotations with Sourcery ๐Ÿ”ฎ

Topics

We first covered Sourcery back in Bite #292. It's a command-line tool that helps us generate Swift code from .stencil template files.

Today we'll check a specific feature of Sourcery, annotations. Let's dive in.

Nefore we begin, let's do a quick "refresher". The TLDR for Sourcery is Render template files into real Swift code. Full access to the type system using SourceKitten. Useful for simple things (automate tasks like adding counts to enums), or crazy complex things (automatically generate Swift test code). Essentially, metaprogramming. Whew. Ok, moving on.

Annotations are simply small bits of metadata that annotate our properties functions, enums, enum cases and other types.

Then, later we can access this metadata inside our .stencil template files.

Let's try it out.

Before we begin, let's add a new Swift Enum to our project. Nothing special here so far, just regular Swift.

enum SpaceshipKind {
    case cruiser
    case frieghter
    case destroyer
}

Next, we'll add a new SpaceshipKind+Count.stencil file for Sourcery to render. We'll use the "Empty" option in Xcode when creating a new file, then open the Inspector (right side) and change the file's type to Swift Source so it will read (slightly) nicer in Xcode.

Finally, let's run sourcery:

sourcery source/ templates/ /source/_generated/ --watch --verbose

Passing in the --watch tells Sourcery to run continuously and re-render our templates anytime our code or templates change. Neat.

The --verbose flag tells Sourcery to print a bunch of useful debug info to the console while it's working. Helpful at first, but once we're more comfortable with Sourcery, we can probably leave this off.

Whew! Now we can finally start using Annotations.

Let's add an annotation to our enum:

enum SpaceshipKind {
    case cruiser
    case frieghter
    case destroyer
}

Then in our template, let's generate a count property for all our enums:

{% for enum in types.enums %}
extension {{ enum.name }} {
  static var count: Int { return {{ enum.cases.count }} }
}
{% endfor %}

This works great:

extension SpaceshipKind {
  static var count: Int { return 3 }
}

But what if we were farther along in our project? What if we had many more Enums in our code base, and wanted to exempt a few of them from generating a count property.

We'll add another new enum:

enum EngineKind {
    case hyperdrive
    case sunsail
}

Since we added some code, Sourcery's --watch kicks in and re-generates our template:

extension SpaceshipKind {
  static var count: Int { return 3 }
}
extension EngineKind {
  static var count: Int { return 2 }
}

Let's pretend we don't need that second enum to get a count property.

There's a few ways we could approach this in Sourcery, but this gives us a nice way to learn about and understand how annotations work.

We'll add one above EngineKind in our code:

/// sourcery: skipCount
enum EngineKind {
    case hyperdrive
    case sunsail
}

Annotations are simply special comments that Sourcery parses, and makes available in our .stencil templates.

The cool part is it's location aware, so we can put annotations above types, and they'll be available on those types in our .stencil templates! Same goes for annotations on properties, enum cases and more!

Now, we can access this annotation in our template:

{% for enum in types.enums %}
extension {{ enum.name }} {
  {% ifnot enum.annotations.skipCount %}
  static var count: Int { return {{ enum.cases.count }} }
  {% endif %}
}
{% endfor %}

Finally, our generated code is back to just the one enum:

extension SpaceshipKind {
  static var count: Int { return 3 }
}

Success!

We can also apply annotations to multiple things at once using :begin and :end tags:

/// sourcery:begin: skipCustomSetter
var captainID: Int
var maxSpeedInParsecs: Int
/// sourcery:end

This is just the beginning. Come back next time to learn about key/value pair annotations.

Learn more about Sourcery at git.io/sourcery (also in Bite #292)

AttributedStrings are a wonderful way for us to describe and add rich, styled text to our apps.

We've covered a few different approaches and solutions for composing AttributedStrings over the years.

Today we'll check out at a new library, Attributed by Nicholas Maccharoli, which stands out as a modern approach to the task. Let's take a look.

We'll start by looking at the "standard" way to use AttributedStrings in Foundation:

let font = UIFont(name: "AvenirNext", size: 18.0)!

NSAttributedString(string: "Han Solo", attributes: [
  NSForegroundColorAttributeName: UIColor.black,
  NSFontAttributeName: font
])

Not too bad, but we can do better. Let's try this same thing but with Attributed:

"Han Solo".attributed(with: Attributes { $0.foreground(color: .black).font(font) })

Neat!

"Why not just use the AttributedString API that ships with Foundation?"

This is a fair question.

Imagine building an app that had many different attributed string styles. With Attributed, we're given a strongly API, allowing us to omit a couple of types. We're also able to omit the long, verbose key names.

Finally, (and perhaps most importantly) we're using a sort of "closure composition" technique.

This involves accepting a Swift closure in an initializer, giving us the anonymous argument $0 to play with. Then, we can chain function calls on to $0 to add attributes.

All of this leads to a dramatic decrease in manual typing (even with autocomplete in Xcode, writing tons of attribute collections stops being fun, quickly).

It also allows us to work more effeciently, and accurately. We can lean on our syntactic shorthand and trust in the Swift's type system to get us to the finish line.

Inheritance

Before we go, let's talk about one of the most common hiccups we can run into when writing AttributedString-related code. Inheritance.

We've all been there. We're composing an AttributedString to go into a UILabel. We're pumped because we've got the style neatly translated from the original design into code. Then we see it. The design calls for one of the words in the label to be a different color, for emphasis.

Dun, dun dun.

No worries though, with Attributed we can solve this problem quickly:

let base = Attributes().font(UIFont(name: "AvenirNext", size: 18.0)!)

let highlighted = base.foreground(color: .red)

"Han Solo is the captain of the ".attributed(with: base)
    + "Millennium Falcon".attributed(with: highlighted)

Very cool. We're able to define a base set of attributes in Attributes(), then compose new sets that inherit all the attributes of our base set.

Then, we're leaning on Attributed's extension to String and String's support of the + operator to write some super clean code.

Pro Tip: This functionality also allows us to easily build up a re-usable set of Attributes(), keeping them in one spot, then sprinkling them throughout our code.

Learn more about Attributed at git.io/attributed.

We cover plenty of libraries and developer tools here on LBOC. Many are useful not just on their surface, but also in terms of how they allow us to learn from our fellow developers.

Through this process, we collectively explore new approaches and techniques. New ideas emerge all the time.

Every now and then, one of these ideas stands out.

Sometimes, an idea makes too much sense, or is simply too useful to ignore.

In modern times, things like Fastlane, CocoaPods, and Carthage come to mind. Slightly more seasoned folks may remember the emergence of Pull to Refresh, or BWToolkit.

Sourcery from Krzysztof Zabล‚ocki is the latest addition to this set.

It brings the concept of "meta-programming" to Swift, and it is definitely too useful to ignore.

Let's peer into our crystal ball, and see what it can do.

At its core, Sourcery generates Swift code from template files.

It elegantly brings together two other great developer tools: SourceKitten (for introspecting our code), and Stencil (for templates).

It aims to solve a few problems:

  • Reduce time spent writing so-called "boilerplate", or repetitive/obvious code.
  • Provide a way to reason about the types in our code, and their properties.
  • Reduce simple human errors, caused by things like typos.

Ok, enough introduction. Here's how Sourcery works:

  • First, we'll write some code that looks almost like regular Swift code into "template" (.stencil) files.
  • Then, we'll run the sourcery command-line tool. This will "render" our .stencil files into .swift files that we'll add to our project.
  • Finally, when we build our app, our "generated" .swift files will get compiled just like any other .swift files we might add.

Immediately some ideas of how to use this begin coming to mind. Here's a few specific tasks that might cause us to reach for Sourcery:

  • Conforming our types to NSCoding.
  • Conforming to Equatable or Hashable
  • Writing JSON de-serialization code

Maintaining each of these implementations is a never-ending task. Anytime we add, remove, or change a property we'll need to potentially revist each of these bits of code as well. Bummer.

Ok. Let's try this thing.

First we'll need to get the sourcery command-line tool. The simplest way to do this is to download the latest release binary here.

Let's cd into the root directory of the download and copy the tool over to somewhere permanent:

cp bin/sourcery /usr/local/bin

(Note: /usr/local/bin is a common place to put command line tools on macOS thanks largely to the fact that Homebrew puts things there, so it's likely already in our $PATH).

Neat. Now we can use it anywhere.

We could also have simply copied the tool into our project, and added it to source control. Any approach is fine, we just need to be able to run it in the root directory of our project somehow.

Now, let's head into that root directory of our project, and create a couple directories:

mkdir templates
mkdir generated

We're almost ready to try things out. First though, we'll need a template to generate from.

Let's add a new file in the templates directory called Enum+Count.stencil. Then, we'll write our first template code:

{% for enum in types.enums %}
extension {{ enum.name }} {
  static var count: Int { return {{ enum.cases.count }} }
}
{% endfor %}

The {{'s, }}'s, {%'s, and %}'s are Stencil template tags.

Stencil deserves a full Bite of it's own, but for now we just need to know that statements within these tags get evaluated by the sourcery command line tool, and iterated or replaced when generating Swift code.

The rest of the content is regular Swift code.

Anyone who has worked on a web app in recent years should feel right at home with this technique. Instead of generating HTML though, we're generating Swift code, neat!

Let's break down what's happening in our template:

First, we want to iterate through all the enums in our project's code:

{% for enum in types.enums %}

{% endfor %}

Then, for each enum we find, we want to extend it to have a new static property called count.

extension {{ enum.name }} {
  static var count: Int { return {{ enum.cases.count }} }
}

This property will return the number of cases in the enum. (Providing us a piece of functionality currently missing from Swift itself).

Finally, we can run sourcery.

./sourcery . templates generated --watch

We've passed in the --watch flag to make sourcery watch our template files, and re-generate them anytime it sees a change. Neat.

This will scan our source code for a bit, then produce a new file in the generated directory called Enum+Count.generated.swift.

It will look like this:

extension SpaceshipKind {
  static var count: Int { return 37 }
}

extension CrewRank {
  static var count: Int { return 10 }
}

extension HTTP.Method {
  static var count: Int { return 7 }
}

How cool is that?

Now, we just need to add this generated file to our Xcode project like we would any other file. Its contents will be replaced anytime sourcery runs.

Pro Tip: We can also optionally add a new "Run Script..." Build Phase to our Xcode project to run the sourcery command (without --watch of course) at the beginning of each build of our app. Very cool.

The Sourcery Github repo offers a some very useful example templates for adding things like Equatable and Hashable. These examples are a great way to learn more about what's possible.

We've of course only barely scratched the surface of what's possible with Sourcery. Look out for future Bites where we'll explore much more...

Learn more and find full documentation of Sourcery at git.io/sourcery

Weekly Sponsor: Zendesk ๐Ÿ’ก

We're welcoming back one of our favorite sponsors this week, it's Zendesk!

None of us have ever built a flawless app.

Chances are, no matter how good we think our app's user experience is, there's probably something users will need help with while they're in our app.

Yet in many apps, getting help is reduced to a "contact us" button that launches an compose email screen, or a just drops the user on a web page.

By forcing folks out of the app to get help, small problems can turn into big annoyances, and those will almost certainly turn into negative App Store reviews and poor ratings.

With Zendesk's Mobile SDKs, we can join the makers of Angry Birds, Venmo and Swiftkey in bringing native, in-app support functionality to our apps quickly and easily.

Our users can view help and support content, and even submit tickets to support without ever leaving our app. Neat!

Tickets go into Zendesk and can include technical details about the user and their device, history with our apps, and more.

Best of all, it's included with Zendesk at no extra charge.

We can use Zendesk's "out-of-the-box" iOS UI components to get up and running quickly, or we can build your own UI with SDK API Providers.

A huge thanks to Zendesk for sponsoring!

We've covered UI Tests a fair amount over the years, but one thing has always stuck out: Running tests can be slow. Very slow.

Even if our individual tests themselves run quickly, the entire process is essentially "single threaded", slow to start up and complete each pass, and is prone to strange errors.

Today we'll take a look at Bluepill, a new tool from LinkedIn that can help us with all of this by running multiple iOS Simulators in parallel, simultaneously. Let's dive in.

We'll start by cloning the repository, then running the build script that comes inside:

./build.sh

This will build the command line tool. Once it's finsihed, we can copy the tool somewhere permanent:

cp build/Build/Products/Debug/bp /usr/local/bin

Then rename it to something we can more easily identify:

mv /usr/local/bin/bp /usr/local/bin/bluepill

(Note: /usr/local/bin is a common place to put command line tools on macOS thanks largely to the fact that Homebrew puts things there, so it's likely already in our $PATH).

Now that we have Bluepill installed, let's try it out.

We can head back to our project and run something like:

./bluepill -a ./Spaceships.app -s ./SpaceshipsUITests.xcscheme -o ./output/

This is great for quick runs, but ideally we'd be able to configure this sort of thing once and use it each time. Let's make a quick configuration file using JSON. We'll call it bluepill-config.json:

{
   "app": "./Spaceships.app",
   "scheme-path": "./SpaceshipsUITests.xcscheme",
   "output-dir": "./bluepill-logs/"
}

By default Bluepill will run 4 iOS Simulators simultaneously. Before we run our tests, let's turn that up a notch by adding one more option to our config file:

(This will cause our test to be run in up to 12 iOS Simulators at once. Very cool).

{
   "app": "./Spaceships.app",
   "scheme-path": "./SpaceshipsUITests.xcscheme",
   "output-dir": "./bluepill-logs/",
   "num-sims": 12
}

Finally, we can start our engines:

./bluepill -c bluepill-config.json

So awesome.

Not only are we saving tons of time this way, but Bluepill also does other helpful things for us, such as automatically retrying when the Simulator hangs or crashes. Neat.

We've only scratched the surface of what's possible with Bluepill. Be sure to check out the README for a full list of options and defaults.

Learn more about Bluepill at git.io/bluepill.

Optimizing for responsiveness is a huge part of making great apps. Before we can optimize though, we'll need to measure. Xcode and Instruments offer some incredible tools to do "deep-dives" for answers (Bite #68, Bite #113), but often we just want to keep an eye on our app's performance and respond as needed.

Today we'll try out a library called GDPerformanceView by Gavrilov Daniil that lets us easily monitor our app's rendering speed and CPU usage in the device's status bar while we use the app. Let's begin.

We'll install GDPerformanceView and head over to our AppDelegate. We'll add a bit of code:

GDPerformanceMonitor.sharedInstance.startMonitoring { (textLabel) in
  textLabel?.backgroundColor = .black
  textLabel?.textColor = .white
}

Here we're telling GDPerofrmanceMonitor to start its engines, then customizing the look and feel of the label that appears in the status bar.

When we Build & Run, here's what we get:

Neat! By default GDPerformanceView will show the app and device version. This is great in some cases (QA testing, beta builds), but in our case we don't really need it. Let's them both off:

GDPerformanceMonitor.sharedInstance.appVersionHidden = true
GDPerformanceMonitor.sharedInstance.deviceVersionHidden = true

Beautiful. Now we'll always know exactly how well our app is behaving, and we'll be able to identify issues as they happen.

GDPerformanceView has one more trick up its sleeve. ๐ŸŽฉ

We can actually subscribe to performance updates and do whatever we'd like with the data.

Let's try this out. First we'll subscribe to updates by making our AppDelegate conform to the provided GDPerformanceMonitorDelegate protocol:

extension AppDelegate : GDPerformanceMonitorDelegate {
  func performanceMonitorDidReport(fpsValue: Float, cpuValue: Float) {
    // TODO
  }
}

Then, we'll set it as the delegate for the shared GDPerformanceMonitor in our didFinishLaunching:

GDPerformanceMonitor.sharedInstance.delegate = self

Nice. Now we need to do something interesting with these updates. Let's use the Taptic Engine (Bite #269) to provide some force feedback if we hit the CPU too hard:

func performanceMonitorDidReport(fpsValue: Float, cpuValue: Float) {
  if cpuValue > 50 {
    UIImpactFeedbackGenerator(style: .heavy)
      .impactOccurred()
  }
}

Neat! We could also toss these values into an array somewhere and use it to build charts, etc.

Learn more about GDPerformanceView at git.io/gdperformance.

Xcode offers a wealth of great tools for debugging. Sometimes though, we'd like to be able to debug or evaluate the inner-workings of our app without needing to be connected to Xcode's debugger.

Today we'll check out TinyConsole by Devran รœnal, a library that lets us easily display our log messages directly inside our app. Let's take a look.

We'll install TinyConsole into our app, then slightly modify some code in our AppDelegate to set it up.

Instead of assigning our root view controller like this:

self.window.rootViewController = SpaceshipsViewController()

We'll wrap our root view controller in a TinyConsoleController:

self.window = TinyConsoleController(
  rootViewController: SpaceshipsViewController()
)

That's it. Now all we need to do is add some log messages throughout our code. We can do this with calls like:

TinyConsole.print("spacehip id: \(spaceship.id)")

Now, we can launch our app and try it out. When running on a device, we can simply shake the device to show/hide the console view.

(Pro Tip: Press โŒ˜โŒƒZ to simulate a shake in the iOS Simulator).

Neat! TinyConsole doesn't stop there though, we can also use colors:

TinyConsole.print("Crew Member Saved!", color: UIColor.green)

and add Markers:

TinyConsole.addMarker()

Finally, there's a few more gestures available (in addition to shaking to hide/show).

We can swipe to add a Marker, tap with 2 fingers to log something manually, or tap with 3 fingers to show an Action Sheet that allows us to send our log messages as an email.

Learn more about TinyConsole at git.io/tinyconsole

This week we're welcoming back one of our favorite sponsors. These folks have been sponsoring for quite a while now, so huge thanks to buddybuild!

Long time readers will remember that buddybuild is a fantastic mobile continuous integration, delivery, crash reporting and feedback platform, all in one.

It takes just minutes to set up, let's check it out!

We'll head over to buddybuild.com and click Get Started.

We'll sign up with Github (we could also use Bitbucket, GitLab, or sign up with email / password for repos on any other git server). Neat!

Next, buddybuild will let us choose a git repo to create our first project with.

 

Once we select the repo we want to build, buddybuild will get to work building our app for the first time.

After that build is complete, our app is set up on buddybuild - it's that easy.

buddybuild installs and configures the necessary web hooks for our project so new builds are triggered whenever code is pushed. It also scans your repo for any tests you might have written, and runs them reliably on the simulator and physical devices.

 

With buddybuild, we won't need to wait for App Store processing time or reviews before deploying to testers.

buddybuild's continuous deployment system can send our app to users instantly on every build, on a schedule that works for our team, or at the push of a button.

Buddybuild's deployment service also handles the process of adding new users (and their devices) by automatically managing UDIDs, iOS provisioning profiles and signing identities. (Fantastic UX for both testers and devs!)


f

 

Only buddybuild goes even farther, and gives us a fully integrated feedback platform.

Once users have installed our app and are testing it out, they can send their feedback (along with important diagnostic details) by simply taking a screenshot.

If our app ever crashes, buddybuild will trace back and highlight the exact line of offending source code that caused the crash, telling us which users were affected, and how many times the crash happened.

Each crash is also recorded with an Instant Replay - this is a video replay of our users' actions in the moments leading up to the crash. Never wonder about "steps to reproduce" again! Super cool.

Buddybuild is also a great community citizen, and has our backs as iOS developers. For example, they'll give us a heads up on any potential breaking changes in Xcode. Within 48 hours of any Xcode release (including betas!), buddybuild will automatically takes our most recent successful build, and build and run tests against it using the latest version of Xcode. Then it will email us the results. How cool is that?!

Last but certainly not least, buddybuild not only comes with built-in integrations with tons of services we all know and love like GitHub, BitBucket, GitLab, Slack, JIRA Pivotal Tracker, Slack, HipChat but it's also infinitely customizable to meet the exact needs of your development team!

Buddybuild is the real deal, give them a try today at buddybuild.com!

In Bite #287, we built a small extension to Date to allow us to format relative date strings like "10 minutes ago". We used a bunch of if statements and built our final String. This was a nice way to learn about working with DateComponents, but it turns out ๐Ÿ›Ž  Foundation actually provides a class to do something similar, and it's much more powerful.

Today we'll continue our look at Foundation's date and time-related functionality with DateComponentsFormatter. Let's dive in.

Much like its cousin DateFormatter (Bite #286), DateComponentsFormatter is all about converting a TimeInterval or DateComponents into a nicely formatted, human-readable String. (Note: It doesn't support parsing Strings yet. Conversions are a one way trip for now).

We'll start with a new formatter:

let formatter = DateComponentsFormatter()

Then we'll configure a few options:

formatter.unitsStyle = .full
formatter.allowedUnits = [.minute, .second]

And finally, we'll ask for a String describing an example TimeInterval:

formatter.string(from: 543.0) // "9 minutes, 3 seconds"

Like many Foundation types, DateComponentsFormatter is a super customizable powerhouse. Let's try a few more options:

formatter.unitsStyle = .abbreviated
formatter.string(from: 123.0)

// "2m 3s"
formatter.unitsStyle = .short
formatter.string(from: 123.0)

// "2 min, 3 sec"
formatter.unitsStyle = .spellOut
formatter.string(from: 123.0)

// "two minutes, three seconds"
formatter.includesApproximationPhrase = true
formatter.includesTimeRemainingPhrase = true
formatter.unitsStyle = .brief
formatter.string(from: 123.0)

// "About 2min 3sec remaining"

Neat. Fun Fact: If you've ever seen a progress bar or "time remaining" bar in iOS or macOS, you've seen a DateComponentsFormatter in action.

We've only been allowing .minutes and .seconds. Let's try allowing some different sets of units:

let formatter = DateComponentsFormatter()

formatter.unitsStyle = .full

formatter.allowedUnits = [.minute, .second]
formatter.string(from: 1234567.0)

// "20,576 minutes, 7 seconds"
formatter.allowedUnits = [.day, .hour, .minute, .second]
formatter.string(from: 1234567.0)

// "14 days, 6 hours, 56 minutes, 7 seconds"
formatter.allowedUnits = [.day, .minute, .second]
formatter.string(from: 1234567.0)

// "14 days, 416 minutes, 7 seconds"

Neat!

These are just the very basics. Look out for some more advanced DateComponentsFormatter fun soon.

Page 5 of 38