Want to offer native, in-app customer service to your users? Get going quickly with Zendesk’s Mobile SDK. Save $177 with coupon code LBOC.

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

Weekly Sponsor: Buddybuild 🤖🛠

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!

Topics

#288: DateComponentsFormatter Basics 📆

Topics

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.

In Bite #286, we looked at the basics of using DateFormatters to transform Dates into Strings.

Today we'll explore another common use case of Dates in our apps: "relative" date strings.

Think "2 days ago", "10 minutes ago", "Yesterday", and "Just now". Representing timestamps this way has become common, and it can help our users more quickly understand how old a piece of content is.

Let's add this functionality to our app by extending Date to give it a new computed property to do this.

We'll begin by adding a new File to our Xcode Project. We'll call it Date+Relative.swift. (The Type+SomeExtensionName convention is borrowed from Objective-C.

Then, we'll set up our extension:

extension Date {
  var relativelyFormatted: String {
    // TODO
  }
}

Nice. Next, we'll need a way to calculate how much time is in between now, and self (from the extended Date's point of view). We could do a bunch of ugly math, but we've got a better way!

This is a fantastic use case for Foundation's DateComponents type. It has a function that can calculate the difference between two Dates, and provide it to us in neatly (pre-calculated) components like days, months, hours, seconds, etc.

We'll begin our implementation like so:

let now = Date()

let components = Calendar.current.dateComponents(
  [.year, .month, .weekOfYear, .day, .hour, .minute, .second],
  from: now,
  to: self
)

We ask the current Calendar to please calculate the quantity of each of the components we passed in for the time between the Date we passed in as the from argument to the Date we passed into the to argument.

Beautiful. Now, the returned DateComponents type has a bunch of properties we'll use to build our relatively formatted date `String.

Finally, we'll inspect each date component (starting with most broad at the top) and return a nicely formatted String:

if let years = components.year, years > 0 {
  return "\(years) year\(years == 1 ? "" : "s") ago"
}

if let months = components.month, months > 0 {
  return "\(months) month\(months == 1 ? "" : "s") ago"
}

if let weeks = components.weekOfYear, weeks > 0 {
  return "\(weeks) week\(weeks == 1 ? "" : "s") ago"
}
if let days = components.day, days > 0 {
  guard days > 1 else { return "yesterday" }

  return "\(days) day\(days == 1 ? "" : "s") ago"
}

if let hours = components.hour, hours > 0 {
  return "\(hours) hour\(hours == 1 ? "" : "s") ago"
}

if let minutes = components.minute, minutes > 0 {
  return "\(minutes) minute\(minutes == 1 ? "" : "s") ago"
}

if let seconds = components.second, seconds > 30 {
  return "\(seconds) second\(seconds == 1 ? "" : "s") ago"
}

return "just now"

Doing things manually like this allows us to completely customize and control exactly how this relative date strings appear in our app.

This is fairly straightforward. We get a little fancy for the "days" component, allowing for "yesterday". We could also easily add support for future dates (i.e. "tomorrow") here as well.

All that's left to do is test it out. We can do that easily by constructing some Dates in the past, then printing our new property:

Date(timeIntervalSinceNow: 1).relativelyFormatted
// "just now"

Date(timeIntervalSinceNow: 12).relativelyFormatted
// "just now"

Date(timeIntervalSinceNow: 58).relativelyFormatted
// "58 seconds ago"

Date(timeIntervalSinceNow: 123).relativelyFormatted
// "2 minutes ago"

Date(timeIntervalSinceNow: 1234).relativelyFormatted
// "20 minutes ago"

Date(timeIntervalSinceNow: 12345).relativelyFormatted
// "3 hours ago"

Date(timeIntervalSinceNow: 123456).relativelyFormatted
// "yesterday"

Date(timeIntervalSinceNow: 1234567).relativelyFormatted
// "2 weeks ago"

Date(timeIntervalSinceNow: 12345689).relativelyFormatted
// "2 months ago"

Date(timeIntervalSinceNow: 123456890).relativelyFormatted
// "3 years ago"

Date(timeIntervalSinceNow: 1234568901)
  .relativelyFormatted // "39 years ago"

Date(timeIntervalSinceNow: 12345689012)
  .relativelyFormatted // "391 years ago"

Topics

#286: DateFormatter Basics 📆

Topics

Formatting dates and times is one of those common tasks we all have to do in almost every app. Today we'll take a look at how to use Foundation's solution for this: DateFormatter.

DateFormatters are incredibly powerful. Their core purpose is transforming Dates into Strings and Strings into Dates. They handle things like localization for us under the hood. Let's try one out.

We'll create a new formatter:

let formatter = DateFormatter()

Then we'll need to set a "format" on it. This is a string of characters that represent the date we're going to try to parse or render. Often these appear as one or more repeated series of letters like:

formatter.dateFormat = "MMM yyyy"

To see a rendered date string using this format, we can ask for one like this:

formatter.string(from: Date()) // "Jan 2017"

We can play around with the format for different results:

formatter.dateFormat = "MMMM yy"
formatter.string(from: Date()) // "January 17"

Neat. Let's try going the other way. We'll pass in a string, and ask our DateFormatter to parse it into a Date for us.

formatter.dateFormat = "MMMM yy"
formatter.date(from: "February 28")

// "Feb 1, 2028, 12:00 AM"

Very cool.

A couple of pro tips before we go:

The first is that DateFormatters have historically been heavy-weight objects to create. Performance has definitely improved over the years, but if we can, it's probably a good idea to keep one around instead of creating on the fly each time we need it. (For example we wouldn't want to be creating a new DateFormatter inside a UITableView or UICollectionView "cell for row" style delegate function).

The second is that these format strings are opaque and hard to understand at a glance. To solve this, friend of the show (and creator of the awesome NSScreencasts) Ben Scheirman has created a site called nsdateformatter.com.

There we can not only find easy, glance-able examples and references for all the different date format tokens, but we can also test out formats right there in the browser! Super handy.

We've only scratched the surface of what Foundation is capable of when it comes to Dates. Tune in tomorrow to learn more.

Weekly Sponsor: Buddybuild 🤖🛠

We've got one of our favorite sponsors back this week, it's 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 to 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.

Now, we'll be able to trigger a new build (and run our tests with code coverage) at any time with a simple git push!

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

 

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

Speaking of deployment, buddybuild's email (and Slack!) based deployment service can deploy instantly on every build, every night, 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!)

 

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's 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 - to show you exactly what your users were doing in the moments leading up to the crash. Awesome!

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 comes with built-in integrations with tons of services we all know and love such as GitHub, BitBucket, GitLab, Slack, JIRA Pivotal Tracker, Slack, HipChat and more!

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

Topics

#285: Generating Random Data with RandomKit 🎲

Topics

Whether we need sample values while prototyping our app's interface, or some multipliers for our game's logic, random data can be incredibly useful when programming. Today we'll check out a great library from Nikolai Vazquez called RandomKit that makes generating random data both simple and intuitive. Let's begin.

RandomKit is built on a set of Swift Protocols. We're provided Random, RandomWithinRange, RandomToValue, and many more. RandomKit then extends a bunch of types to conform to these protocols.

(This is great because it means we can easily add RandomKit-style functionality to our own types, if we ever need to. Neat.)

Let's try out the basics. Some of the most common things to generate randomly are numbers and booleans. RandomKit has us well covered here, supporting all the major numerical Foundation types (and more):

Double.random() // 0.6472946529383645
Int.random(within: 1...10) // 7
NSNumber.random(within: -5...5)  // -3
CGFloat.random(0...1)  // 0.27969591675319
Bool.random() // false

Neat. Next up, Strings:

String.random(ofLength: 5) // "$-=5t"
Character.random() // "#"

We can also easily grab a random element from any Swift Sequence or Collection:

"Little Bites of Cocoa".characters.random // "o"
["Han", "Luke", "Chewie"].random // "Luke"
NSDictionary(dictionary: [ "firstName": "Han", "lastName": "Solo" ]).random // ("lastName", "Solo")

But wait, there's more! RandomKit is incredibly comprehensive. Let's try some more advanced functionality like Dates:

Date.random(within: Date.distantPast...Date())  // "Feb 7, 472, 5:40 AM"

URLs:

URL.random() // https://stackoverflow.com

...or even UIColors and NSColors:

UIColor.random(alpha: false)  

Last but not least, we can even grab random values for CoreGraphics types:

CGPoint.random(within: 0...50, 0...50) // {x 23.284 y 45.302 }
CGSize.random(within: 0...50, 0...50) // {w 29.475 h 12.863 }
CGRect.random() // {x 3.872  y 46.15  w 8.852  h 20.201}

These examples were just a (sorry) random-sampling of RandomKit's functionality. It has a ton more to offer.

Learn more about RandomKit at git.io/randomkit

Page 2 of 35