Active Filters: Libraries

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

UITableView & UICollectionView have some fantastic animation capabilities. We can animate items and sections being inserted, removed, moved, etc. We've all been there though, reloadData is sitting right there, and is conceptually so simple. Wouldn't it be great if we could enable those fancy animations in our views, with the conceptually simplicity of reloadData?

Today we'll check out Dwifft, a library from Jack Flintermann that can help us achieve this. Let's dive in.

We'll begin with a regular UITableViewController. (Dwifft works just as well on UICollectionViews).

First we'll need a TableViewDiffCalculator. This is a generic type, so we'll tell it that we're going to be display a bunch of Strings.

class ExampleViewController: UITableViewController {
  var diffCalculator: TableViewDiffCalculator<String>?

Next we'll initialize our data with some random items (just a randomly ordered array of Strings). We'll also use a property observer to let our diff calculator know whenever our items change.

var items: [String] = ExampleViewController.randomItems() {
  didSet { self.diffCalculator?.rows = items }
}

We're almost there. We'll initialize the diff calculator in our view controller's viewDidLoad function:

override func viewDidLoad() {
  super.viewDidLoad()

  tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ItemCell")

  diffCalculator = TableViewDiffCalculator<String>(
    tableView: tableView,
    initialRows: items
  )
}

Lastly, we'll implement a couple of standard UITableViewDataSource functions:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return items.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
  cell.textLabel?.text = selfitems[(indexPath as NSIndexPath).row]
  return cell
}

Success! Here's how this ends up looking:

The "Shuffle" button was wired up off-camera, but it simply sets self.items = ExampleViewController.randomItems().

Now we can simply update the diff calculator's rows and we'll get all those beautiful, scroll-position preserving animations automatically.

A couple of final notes, we can customize the individual animation types like this:

diffCalculator?.insertionAnimation = .fade
diffCalculator?.deletionAnimation = .fade

And finally for fun the science behind Dwifft is pretty neat to read about. Read more about the Longest Common Subsequence Problem here.

Learn more about Dwifft at git.io/dwifft

Alerts have been around since iOS was iPhone OS. First in the form of UIAlertView, and now through UIAlertController (Bite #44). The built-in system alerts work great, but sometimes we want something fancier 🎩. Today we'll check out PMAlertController from Paolo Musolino, a library that allows us to easily display great looking alerts in our app. Let's take a look.

PMAlertController is essentially a fancier replacement for the styles that UIKit's UIAlertController already provides.

PMAlertController two styles of alerts: "Alert" and "Walkthrough".

The "Alert" Style is 270 points wide (matching the system's alerts):

The "Walkthrough" Style is almost the full width of the screen and is appropriate for more in-depth alerts/dialogs (such as those for explaining why our app is requesting permission for some of the user's data):

Using PMAlertController is almost just like UIAlertController.

We're given a title, description and image to work with:

let alertVC = PMAlertController(
  title: "Locate your device", 
  description: "Enables access to your...",
  image: UIImage(named: "flag.png"),
  style: .alert
)

alertVC.addAction(PMAlertAction(
  title: "Cancel", style: .cancel,
  action: { in }
))

alertVC.addAction(PMAlertAction(
  title: "Allow", style: .default,
  action: { in }
))

present(alertVC, animated: true, completion: nil)

We instantiate the view controller, add some actions (each with their own closure handler that will be called when the action is tapped), and present it.

Neat!

Libraries like PMAlertController can help us easily add some polish to our apps, but they can also be a great way to learn about creating custom controls in general.

Learn more about PMAlertController at git.io/pmalert

Topics

#270: Implementing Theming with CostumeKit 🎩

Topics

We've looked at protocols in Swift in Bite #232, but we haven't really seen a ton of "real world" examples. Today we'll check out a library called CostumeKit. It's a set of base protocols that can assist us in visually styling or "themeing" our apps. Along the way we'll use some protocols "for real". Let's jump in.

Author's Note: Full disclosure, CostumeKit is written by me. I'm a huge fan of conventions, also it's a nice basic example of Protocols. I use it in all my apps.

To try this out, we'll be working on an imaginary Little Bites of Cocoa app.

We'll start by adding CostumeKit to our project with Carthage:

github "jakemarsh/CostumeKit"

Next, we'll start implementing our types. First up is the colors we'd like to use.

We'll make an enum and paste in all the colors we want to use, giving each a friendly name:

public enum LittleBitesColors : Color, ColorPalette {
  case beige = "FEFAF1"
  case lightBrown = "AB9372"
  case brown = "8C5637"
  case lightGray = "ECECEC"
  case darkGray = "6A6A6A"
  case sponsorRowGray = "F5F5F5"
}

Sharped-eyed-readers will actually recognize this technique from Bite #255 on Creating a ColorConvertible Protocol.

Moving along, LBOC uses the Source Sans Pro font. Let's implement CostumeKit's Font protocol for this. We'll add the font files to our app then implement the protocol:

public struct LittleBitesFont : Font {
  public init(size: FontSize = .textStyle(.body)) {
    self.size = size
  }

  // Font

  public var size: FontSize

  // FontConvertible

  public var FontValue: UIFont {
    return UIFont(name: "SourceSansPro", size: pointSize)!
  }
}

We're almost there, next we need to create the actual Costume our app will wear. For this we'll implement one more protocol. This protocol has no requirements. It serves as more of a convention really.

open class LittleBitesCostume : Costume {
  let spacing = CGFloat(8)

  public func wearRootBackground(_ view: UIView) {
    view.backgroundColor = Color.white.colorValue
  }

  public func wearHeadline(_ label: UILabel) {
    label.font = LittleBitesFont(size: .textStyle(.title1)).fontValue
    label.textColor = contentTextColor().colorValue
  }
  public func contentTextColor() -> Color {
    return LittleBitesColors.darkGray
  }

  public var name: String { return "Default" }
  public var description: String { return "The default costume." }

  public init() { }
}

For good measure, we'll define a night-mode costume as well:

open class LittleBitesNightCostume : LittleBitesCostume {
  public override func contentTextColor() -> Color {
    return Color.white
  }

  override public var name: String { return "Night Mode" }
  override public var description: String { return "For reading in the dark." }
}

That's where CostumeKit stops. We get a super-tiny bit of functionality "for free" (fonts, color parsing), but the idea is that we're merely following a set of conventions to help guide us through writing this code.

Let's finish up by looking at how we might actually use costumes in our app. Everything from this point on would live inside our app's code (and isn't part of CostumeKit).

We'll make a Wardrobe type and static instance to manage all our costumes:

import CostumeKit

public class Wardrobe {
  private(set) var current: LittleBitesCostume

  init(initialCostume: LittleBitesCostume) {
    current = initialCostume
  }

  public func change(costume: LittleBitesCostume, animated: Bool = true) {
    // TODO: In the future, we'll animate this change using UIView transitions and RxSwift.

    current = costume
  }
}

public let wardrobe = Wardrobe(initialCostume: LittleBitesCostume())
public var costume: LittleBitesCostume { return wardrobe.current }

Now in our regular UIKit code, we can use our current costume:

let headlineLabel = UILabel()
headlineLabel.text = "Hello World".
costume.wearHeadline(headlineLabel)

Learn more about CostumeKit at git.io/costumekit

Xcode Project folders can be a messy place. Today we'll check out a tool from the folks at Venmo that can help us tidy up called Synx. Let's take a look.

At its core, Synx's main purpose is to reorganize the files and folders in our Xcode project folder to match the groups and structure we've setup inside Xcode's Navigator pane.

We can start by organizing a project full of content:

Then we'll install Synx:

gem install synx

Then we can simply head into our project's directory and run the main command:

synx ./OCMock.xcodeproj

Synx will work its magic and re-organize our files on disk, creating directories and moving files as needed to make things match the groups in our project.

Additionally, we can also use Synx to remove files no longer referenced in our project, like this:

synx --prune ./OCMock.xcodeproj

We're also provided a couple arguments to help us control how Synx behaves.

We can exclude files:

synx --exclusion /OCMockTests ./OCMock.xcodeproj

Last but not least, for those of us who like to manually sort our files by concept rather than name, we can disable sorting:

synx --no-sort-by-name ./OCMock.xcodeproj

Choosing how to organize projects can be a very subjective and personal choice, this is just one approach. Always use whatever works best.

Learn more about Synx at git.io/synx.

Testing network requests can be tricky. Generating mock data, handling HTTP routes, etc. Thing get complicated quickly. Today we'll check out a library from devlucky called Kakapo that can help us tame all this. Let's get started.

One of the best features of Kakapo is how easy it is start using. We can create a new Router for a domain, and start adding intercepted routes like this:

let router = Router.register("http://littlebitesofcocoa.com")

router.get("/bites") { request in
  return ["id" : 1, "title": "#1: View Controller Initialization 🚀"]
}

In the above example, we're returning static data. Let's kick things up a notch and return some dynamic data. This is another place Kakapo really shines:

let db = KakapoDB()
db.create(Bite.self, number: 10)

router.get("/bites") { request in
  return db.findAll(Bite.self)
}

We can use this functionality to not only test network requests, but even to "stub out" responses before fully implementing backend services. Neat!

Once we've wired up some routes, we can make our network requests like normal:

let URL = NSURL(string: "http://littlebitesofcocoa.com/1")!

session.dataTaskWithURL(URL) { (data, _, _) in
  // handle response
}.resume()

We can even wire Kakapo up to Alamofire (Bite #93) like this:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.protocolClasses = [KakapoServer.self]
let manager = Manager(configuration: configuration)

This barely scratches the surface of what Kakapo has to offer.

From advanced dynamic mocking and database functionality, great routing, and a squeaky clean API, it's definitely worth a look.

Learn more about Kakapo at git.io/kakapo

Page 2 of 10