Active Filters: Libraries

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

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

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

Properly responding integrating with the software keyboard is a big part of building a solid iOS app. Traditionally, this would involve observing NSNotificationCenter notifications and some pretty lengthy boilerplate code. Today we'll look at a great little library from Toto Tvalavadze called Typist that can improve all this. Let's check it out.

Typist works by exposing a way for us to easily "opt-in" to certain keyboard events:

Typist.shared
  .on(event: .didShow) { (options) in
    // TODO
  }
  .start()
}

Yep. That's it. Gone are the wildly verbose notifications and complicated setup.

(Note: We're not required to use Typist's singleton instance, but it's provided for convenience).

Typist provides this same interface for a bunch of useful events:

Typist.shared
  .on(event: .willShow) { _ in /* TODO */ }
  .on(event: .didShow) { _ in /* TODO */ }
  .on(event: .willHide) { _ in /* TODO */ }
  .on(event: .didHide) { _ in /* TODO */ }
  .on(event: .willChangeFrame) { _ in /* TODO */ }
  .on(event: .didChangeFrame) { _ in /* TODO */ }
  .start()
}

Finally, inside each event closure, we're given a Typist.KeyboardOptions type that contains strongly-typed properties describing the event:

Typist.shared
  .on(event: .willShow) { (options) in
    guard options.belongsToCurrentApp else { return }

    updateLayout(for: options.endFrame)
  }
  .on(event: .willHide) { (options) in
    guard options.belongsToCurrentApp else { return }

    updateLayout(for: options.endFrame)
  }
  .start()
}

Here we're guard-ing to make sure the keyboard belongs to our app, and returning early if not.

Then, we use the endFrame property to adjust our own views to accomodate the keyboard.

Neat!

Typist's options type also provides startFrame, animationCurve, and animationDuration properties to help us match our app's animation to the keyboard's.

Learn more about Typist at http://git.io/typist

Validating data is usually one of the "chores" we encounter while building apps. It can be annoying and boring code to write, and can be a huge source of bugs. Today we'll check out a great library called FormValidatorSwift that can help us avoid all these issues. Let's take a look.

The core of FormValidatorSwift is built around checking if a String passes some sort of test to be deemed 'valid'.

We'll use individual Conditions or combined sets of Conditions called Validators. We'll attach these to controls like Text Fields and Text Views to allow them to be validated.

Let's try out the included ValidatorTextField to validate an email address:

let field = ValidatorTextField(validator: EmailValidator())

Then, we'll configure it to allow the user to begin entering an email address that's invalid like "hello@", and specify that it should only be validated when it loses focus.

field.shouldAllowViolation = true
field.validateOnFocusLossOnly = true

This sets us up perfectly for our final steps: Displaying the validation info.

First, we'll set the validatorDelegate:

field.validatorDelegate = self

Then, we'll implement one function to update the visual state of our field when the validation state changes:

func validatorControl(validatorControl: ValidatorControl, changedValidState validState: Bool) {
  guard let view = validatorControl as? UIView else { return }

  if validState {
    view.backgroundColor = UIColor.white
    errorLabel.hidden = true
  } else {
    view.backgroundColor = UIColor.red
    errorLabel.hidden = false
  }
}

And finally, we'll add one more function to display the actual reason that validation failed (if it failed):

func validatorControl(validatorControl: ValidatorControl, violatedConditions conditions: [Condition]) {
  var errorText = ""

  for condition in conditions {
    errorText += condition.localizedViolationString
  }

  errorLabel.text = errorText
  errorLabel.hidden = false
}

Last but not certainly not least, we can group our fields into a provided Form type, then ask if the whole thing is valid:

var form = ControlForm()

form.addEntry(field)
form.addEntry(anotherField)

print(form.isValid) // true

Learn more about FormValidatorSwift at git.io/formvalidator

Xcode Source Editor Extensions are really starting to come into their own. Today we'll look at one that solves an age-old annoyance for Xcode users: Importing.

We've all been there. We're deep down in the depths of file, and we realize we need to import a module. We dutifully scroll all the way up, type the import, then scroll back down trying to find our place, and get back in "the zone". Yuck.

Let's try out a new Source Editor Extension (Bite #239) from Marko Hlebar called Import.

As the name suggests, it allows us to type an import Module statement anywhere, then press a keyboard shortcut and have the import fly to the top where it belongs.

Let's try it out.

After installing the extension, we'll import CoreGraphics.

Xcode's Autocomplete still works here to help us find the module we want to import. Neat!

By default the keyboard shortcut is Command + Control + P. This trigger is also available via the menu item: Editor > Import > โ˜๏ธ.

Success! Now we don't have to lose our place, or our train of thought when we need to import something.

Learn more about Import (including full installation instructions) at git.io/import

Attributed Strings are a fantastic way to work with rich, styled-text. (We've covered them in Bites #143 & #144 for the curious.) We've even looked at ways to improve upon how verbose the Foundation NSAttributedString API can be.

Today we'll check out another approach using a library from Eddie Kaiger called SwiftyAttributes. It dramatically improves how we work with Attributed Strings. Let's dive in.

Let's start by looking at how things work in vanilla Foundation:

let attributes: [String: AnyObject] = [
  NSFontAttributeName: UIFont(name: "AvenirNext", size: 16.0)!,
  NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue),
  NSForegroundColorAttributeName: UIColor.gray
]

let someString = NSAttributedString(string: "Hello World", attributes: attributes) 

The functionality is wonderful, but even in fairly standard usage thie code can prove a bit difficult to parse at a glance.

Now, let's create the same string, but let's use SwiftyAttributes's API:

let someString = "Hello World"
  .withFont(UIFont(name: "AvenirNext", size: 16.0)!)
  .withUnderlineStyle(.styleSingle)
  .withTextColor(.gray)

Neat!

Things get even nicer when we need to concatenate two NSAttributedStrings together. We've all had to do this before and it could have involved applying attributes to specific ranges, etc. Now, we can use a much more declarative and readable syntax:

let someString = "We can easily ".withFont(.systemFont(ofSize: 16)) +
                 "underline"
                   .withFont(.systemFont(ofSize: 16))
                   .withUnderlineStyle(.styleSingle) +
                 " certain words.".withFont(.systemFont(ofSize: 16))

Under the hood, SwiftyAttributes takes a pragmatic approach by extending both Swift's String type as well as NSAttributedString with a fairly comprehensive set of delicious, sugary functions:

func withFont(_ font: UIFont)
func withParagraphStyle(_ style: NSParagraphStyle)
func withTextColor(_ color: UIColor)
func withBackgroundColor(_ color: UIColor)
func withLigatures(_ ligatures: Ligatures)
func withKern(_ kernValue: Double)
func withStrikethroughStyle(_ style: NSUnderlineStyle)
func withUnderlineStyle(_ style: NSUnderlineStyle)
func withStrokeColor(_ color: UIColor)
func withStrokeWidth(_ width: Double)
func withShadow(_ shadow: NSShadow)
func withTextEffect(_ effect: String)
func withAttachment(_ attachment: NSTextAttachment)
func withLink(_ link: URL)
func withBaselineOffset(_ offset: Double)
func withUnderlineColor(_ color: UIColor)
func withStrikethroughColor(_ color: UIColor)
func withObliqueness(_ obliquenessValue: Double)
func withExpansion(_ expansion: Double)
func withWritingDirections(_ directions: [WritingDirection])

This allows us to get creative with how we mix and match the two types:

let someAttributedString = fromSomewhereElse()

let someString = someAttributedString + "\n\nNeat!".withTextColor(.brown)

Learn more about SwiftyAttributes at git.io/swiftyattributes

In some cases, Swift Initializers can be a pain to implement.

They can often be 100% boilerplate code, and feel like a chore to write.

This issue is at its worst when defining we're Swift Structs in a framework or module.

In Swift, Structs are automatically given a synthesised initialiser... with an internal modifier. Doh. ๐Ÿ˜ฃ

This means the initializer is only accessible/visible inside the module we're defining it in.

This means we're stuck needing to manually add our own initializers for each of our Structs.

Creating and keeping these initializers up to date can add up to a ton of boilerplate code maintence. Yuck.

Today we'll try out an Xcode Source Editor Extension (Bite #239) from Bouke Haarsma that can help us write these automatically.

The extension works by taking the Swift properties defined within our selected text and converting them to parameters in a Swift Initializer.

After we install the extension, we can write up an example Struct in our code to try it out:

public struct Record {
  public let name: String
  public let type: UInt16
  public let unique: Bool
  public let ttl: UInt32
  var data: Data
}

We'll select just the properties, then select Editor > Generate Swift Initializer > Generate Swift Initializer.

Success! We just saved ourselves a ton of time, and typing. Neat!

Learn more about SwiftInitializerGenerator (including complete installation instructions) at git.io/swiftig

Page 1 of 9