Active Filters: Libraries

Today we'll look at a new library from Krzysztof Zabล‚ocki called KZFileWatchers. It allows us to easily monitor local and remote files, running code when changes occur. Let's dive in.

Watching files for changes is a common technique used when creating "live" updating interfaces.

This is a popular technique among web developers. For example, it's now common to use a tool to "live reload" a web page whenever a CSS file is changed.

Live updating techniques can dramatically change how we work, allowing us to try out changes more rapidly.

KZFileWatchers helps us build this type of functionality by providing two simple tools:

FileWatcher.Local is for observing local file changes. (It can even cross sandbox boundaries for debug simulator builds, think "config files on the desktop").

FileWatcher.Remote is for observe remote file changes. We can place a file on a server somewhere, and KZFileWatchers will use the Etag headers and Last-Modified-Date. This even works with Dropbox. Neat.

Let's use a FileWatcher.Local to make a live updating label.

First we'll create a label:

let textLabel = UILabel()

Then we'll create our file if it doesn't already exist:

let filename = "label-content.txt"
let middle = FileWatcher.Local.simulatorOwnerUsername()
let path = "/Users/\(middle)/Desktop/\(filename)"

if FileManager.default.fileExists(atPath: path) == false {
  try! "Hello, world."
    .data(using: String.Encoding.utf8)?
    .write(to: NSURL.fileURL(withPath: path))
}

Finally, we'll wire up a watcher to our file's path, and update our label when the file changes:

let watcher = FileWatcher.Local(path: path)

try! watcher?.start {
  switch $0 {
  case .updated(let data):
    textLabel.text = String(
      data: data,
      encoding: String.Encoding.utf8
    )
  default: break
  }
}

We can use this technique to drive all sorts of systems. With this we can easily enable/disable features, change content of labels in our UI, or build a full fledged theming system that updates in "real time".

More info about KZFileWatchers can be found at git.io/filewatchers

When using UIImageViews, sometimes the built-in content modes can cramp our style.

Many times, we're displaying photos of people. In these cases, it'd be great if the image view could somehow be told to intelligently crop the photo around the person's face.

Today we'll check out a library from Beau Nouvelle called AspectFillFaceAware. It's super simple, let's take a look.

AspectFillFaceAware is essentially just an extension on UIImageView. It provides two ways to configure an image view to be "face aware".

The first is in Interface Builder, we can enable the feature by flipping on the feature in the Inspector. (Not seeing the option? Run your project once, then it should appear).

Here's the how it looks:

We can also enable the functionality in code by setting the image view's image using this new function:

imageView.set(image: avatar, focusOnFaces: true)

We can even throw a quick corner radius on the image view's layer to try out the "face aware" functionality on a circular view. (i.e. user avatars):

let radius = imageView.bounds.size.width / 2.0
imageView.layer.cornerRadius = radius

Under the hood, the library is using a low accuracy CIDetector with a type of CIDetectorTypeFace to handle the actual face detection. Want to dive deeper here? We covered CIDetectors way back in Bite #87.

More info about AsyncFillFaceAware can be found at git.io/faceaware

With all the WWDC excitement recently, it might have been easy to miss a wonderful new library release from the fine folks at Lickability. It's called PinpointKit and it can completely transform how we collect feedback from users testing our apps. Let's check it out!

After integrating PinpointKit into our app via CocoaPods/Carthage, or just manually, we can trigger a new bug report like this:

PinpointKit.defaultPinpointKit
  .show(fromViewController: self)

We're provided a Configuration struct where we can customize the look and feel, and a PinpointKitDelegate to hook into the state of the feedback being sent.

Now, whenever a user reports a bug they'll be able to:

  • Send along system logs automatically (opt-in)
  • Add arrows, boxes, and text to screenshots
  • Redact sensitive info before reporting

By default PinpointKit reports via Email, but this, (and just about everything else) is completely customizable.

Learn more about PinpointKit at http://git.io/pinpointkit

In Bite #231, we took a look at Realm's new Fine-grained notifications functionality. Today we'll build upon this by checking out another new Realm feature: Queryable, Live Inverse Collections. Whew! That's a fancy name. This feature deserves one though, let's check it out.

Here's a Realm object with a relationship defined on it:

class Person: Object {
  dynamic var name = ""
  let dogs = List<Dog>()
}

That dogs property can be used in a query, and it will even stay updated to reflect changes to the property's value made elsewhere in our app, automatically.

None of that is new though. What is new is the inverse of this mechanic.

Meet the all-new LinkingObjects:

class Dog: Object {
  dynamic var name = ""
  dynamic var age = 0
  let owners = LinkingObjects(
    fromType: Person.self, 
    property: "dogs"
  )
}

Here's what we get for defining things this way:

LinkingObjects are live and auto-updating. When new relationships are formed or removed, they will update to reflect the new state.

LinkingObjects can be used In queries, natively. (Previously this would need to be done in our code):

// People that have a child that have a parent named Diane.
realm.objects(Person).filter("ANY children.parents.name == 'Diane'")

// People whose parents have an average age of > 65.
realm.objects(Person).filter("parents.@avg.age > 65")

LinkingObjects behave like regular Realm collections:

// Which of my parents are over the age of 56?
self.parents.filter("age > 56")

  // Calculate the age of my parents.
self.parents.average("age")

More info about Realm can be found at realm.io

Animation plays a key role in how we understand the user interfaces in the software we use. This role expands itself when animations are driven directly from a user's gestures or interactions with the interface. Today we'll look at a new framework that can help us create these types of experiences without breaking a sweat. Let's dive in.

It's called Interpolate and it's by Roy Marmelstein.

As the project's README puts it: "all animation is the interpolation of values over time."

Interpolate helps us describe the relationships that we want to exist between a user's gesture and the interpolated values that should result for the properties of our views. Let's try it by animating a color.

let colorChange = Interpolate(
  from: UIColor.whiteColor(),
  to: UIColor.redColor(),
  apply: { [weak self] (result) in
    if let color = result as? UIColor {
      self?.view.backgroundColor = color
    }
  }
)

The Interpolate type holds some configuration, next we'll want to wire it up to a gesture:

func handlePan(recognizer: UIPanGestureRecognizer) {
  let translation = recognizer.translationInView(self.view)
  let translatedCenterY = view.center.y + translation.y
  let progress = translatedCenterY / self.view.bounds.size.height

  colorChange.progress = progress
}

Since Pan GRs report every step of their progress as a simple float (from 0.0 - 1.0), we can simply set that progress percentage value directly on the Interpolate object.

There's tons more too, Interpolate supports easing functions, and works on all sorts of foundation types (points, rects, colors, etc.).

More info about Interpolate can be found at git.io/interpolate

We first looked at Realm way back in Bite #49. It's a great data storage solution for our mobile apps. Today we'll start looking at some of the latest improvements in Realm and the new capabilities they offer. First up is Fine-grained notifications. Let's dive in:

Realm has offered notifications of write operations for a while, they look like this:

let token = realm.addNotificationBlock { notif, realm in
  // TODO: viewController.updateUI()
}

These are still around and work great, but it might help to know more about what changed. That's where the new Collection Notifications come in.

Collection notifications give us access the changes that just occurred at a fine-grained level, including the specific indices of insertions, deletions, etc

let results = try! Realm().objects(Spaceship).sorted("name")
let token = results.addNotificationBlock { (changes: RealmCollectionChange) in
  // TODO: self.processChanges(changes)
}

changes here is an enum that looks like this:

public enum RealmCollectionChange<T> {
  case Initial(T)
  case Update(T, deletions: [Int], insertions: [Int], modifications: [Int])
  case Error(NSError)
}

.Update's values can be easily mapped to NSIndexPath objects suitable for use in table views and collection views.

Here's a complete example showing all of this in action:

class SpaceshipsViewController: UITableViewController {
  var notificationToken: NotificationToken? = nil

  override func viewDidLoad() {
    super.viewDidLoad()
    let realm = try! Realm()
    let results = realm.objects(Spaceships).filter("maxSpeed > 0")

    // Observe Results Notifications
    notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
      guard let tableView = self?.tableView else { return }
      switch changes {
      case .Initial:
        // Results are now populated and can be accessed without blocking the UI
        tableView.reloadData()
        break
      case .Update(_, let deletions, let insertions, let modifications):
        // Query results have changed, so apply them to the UITableView
        tableView.beginUpdates()
        tableView.insertRowsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) }, withRowAnimation: .Automatic)
        tableView.deleteRowsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) }, withRowAnimation: .Automatic)
        tableView.reloadRowsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) }, withRowAnimation: .Automatic)
        tableView.endUpdates()
        break
      case .Error(let error):
        // An error occurred while opening the Realm file on the background worker thread
        fatalError("\(error)")
        break
      }
    }
  }

  deinit {
    notificationToken?.stop()
  }
}

More info about Realm can be found at realm.io

Markdown is awesome. For those not familiar, read up on why Markdown is awesome in this fantastic post by Brett Terpstra.

When it comes to using Markdown on iOS and OS X, there's tons of options. Today we'll look at one popular solution from Simon Fairbairn called SwiftyMarkdown. It helps us translate Swift Strings containing Markdown into NSAttributedStrings. Let's take a look.

let md = SwiftyMarkdown(string: "# SwiftyMarkdown\nConverts *Markdown* files and strings into NSAttributedString")
md.attributedString()

It's that simple! SwiftyMarkdown will use some defaults for fonts, colors, etc. Customizing those is quite simple:

md.body.fontName = "AvenirNextCondensed-Medium"

md.h1.color = UIColor.redColor()
md.h1.fontName = "AvenirNextCondensed-Bold"

md.italic.color = UIColor.blueColor()

We can supply custom colors and fonts for each different tag, SwiftyMarkdown even supports inline links, neat!

More info about SwiftyMarkdown can be found at git.io/swiftymarkdown

UISegmentedControl is great, but it's not animated, and has limits to how much you can customize it. UISwitch is great too, it is animated, but it's limited to a yes/no choice, and customization again can be quite tricky. Today we'll look at a library from George Marmaridis called BetterSegmentedControl that aims to helps us here.

Let's try it out in a navigation bar:

let c = BetterSegmentedControl(titles: ["Lights On", "Lights Off"])

c.frame = CGRect(x: 35.0, y: 40.0, width: 200.0, height: 30.0)
c.cornerRadius = 3.0
c.titleFont = UIFont(name: "Avenir", size: 13.0)
c.backgroundColor = .darkGrayColor()
c.titleColor = .lightGrayColor()
c.selectedTitleColor = .whiteColor()
c.bouncesOnChange = false

navigationItem.titleView = c

Awesome! More info about BetterSegmentedControl can be found at git.io/bsc

Creating good-looking animations can be a lot of work. We could spend our whole day learning about curves and scaling, and transforms, and oh boy...

Instead, what if we could simply apply some popular animations to our UI elements with almost no effort at all? Today we'll check out a library called Spring that allows us to do just that.

Spring supplies a ton of common animations like shake, pop, squeeze, wobble, etc.

If we're using Interface Builder, we actually don't even need any code at all. We just use one of Spring's UIView-subclasses, then we supply our animation by name.

In code, it's equally simple:

layer.animation = "shake"
layer.animate()

These all work great out of the box, but we can still customize the curve or individual properties if needed. Neat!

More info about Spring can be found at git.io/spring

Our apps can do tons of useful things with users' data. Before we can though, we must always ask for their permission. Whether it's their physical location, photos, or contacts, the user is always in control of when and how we can access their data.

Each of these respective APIs has it's own way of asking the user if they will allow us to access the data within.

Today we'll check out a library called Permission that unifies all of these permission request into one beautiful API. Let's dive in.

We begin by declaring which piece of data we'd like access to:

let permission: Permission = .Photos

At this point, permission.status will report .NotDetermined (as we'd expect). Next we'll request the permission, this is what causes the prompt to be presented to the user:

permission.request { status in
  switch status {
  case .Authorized:    print("yay!")
  case .Denied:        print("boo")
  case .Disabled:      print("boo boo")
  case .NotDetermined: print("ยฏ\_(ใƒ„)_/ยฏ")
  }
}

But wait, there's more!

Permission is smart. If we request access to something the user has already said โ€˜no' to, it will present an alert (with customizable title/message/buttons) that allows the user to jump to the part of Settings.app needed to flip the switch back to โ€˜yes'.

Additionally, Permission also provides a PermissionSet type to do this on groups of permissions (i.e. Contacts + Camera + Photos).

There's also a PermissionButton (a UIButton subclass) that can display the current permission state, and prompt when tapped.

More info about Permission can be found at git.io/permission

Page 3 of 10