Active Filters: Foundation

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

Often when working with data from an API or third-party we'll need to manipulate or analyze it in a very specific way. In these cases, many of us simply search Google for "how to do the thing to a String in Swift". This usually works out fine, but what a bummer.

Today we'll check out a library from Andrew Mayne called SwiftString, which can help us here.

SwiftString is essentially a collection of a ton of String manipulation and analysis utilities. It has functions like this:

"<rock>blah</hardplace>".between("<rock>", "</hardplace>") // "blah"
"hello".isNumeric() // false
"hello7".isNumeric() // false
"31.0".isNumeric() // true
"-31.0".isNumeric() // true
"star wars".split(" ")[0] // "star"
"star wars"[0...1] // "st"
"#203: Simplifying Common String Operations".slugify() // "203-simplifying-common-string-operations"
"Some [string], *with* %junk in it.)".stripPunctuation() // "Some string with junk in it"
"yay &quot;strings&quot;".decodeHTML() // "yay \"strings\""

We might only need one or two of these functions in a single app, but thanks to SwiftString, we'll never have to write them ourselves again.

More info about SwiftString can be found at git.io/swiftstring

Today we'll follow up with another Bite in our localization series (sort of). Units of measurement are important to get right when localizing our apps for different cultures.

Today we'll look at a library from Khoa Pham called Scale that can help us convert between different units of measurement (for either localization or just-for-fun purposes). Let's begin.

Scale makes it incredible simple to work with different units of measurement:

let length = 5.kilometer + 7.meter  // 5,007 meters
let weight = 10.0.kilogram * 5.gram // 50,000 grams

Everything is strongly-typed, and conversion is a breeze:

2.week.to(unit: .hour) // 336 hours

Scale even provides nicely formatted debug output. For example, print'ing that last statement logs:

Time(value: 336.0, unit: Scale.TimeUnit.hour)

Scale supports a wide variety of units:

let angle = 5.degree + 2.radian
let area = 5.acre + 2.hectare
let metric = 5.base + 2.kilo
let volume = 5.liter + 2.gallon
// + many more...

One more example to show off how readable Scale's API is. Here we'll add two typed units together, then convert them:

let time = 4.day + 1.week
print(time.to(unit: .week))
Time(value: 1.57142857142857, unit: Scale.TimeUnit.week)

More info about Scale can be found at git.io/scale

.stringsdict files were added in iOS 7 and OS X 10.9. They allow us to "pluralize" text in our app without a bunch of switch or if statements.

let spaceships = [Spaceship(selected: true)]

let pluralized = String.localizedStringWithFormat(
  NSLocalizedString("%d ships selected",
    comment: "how many ships selected"),
  spaceships.filter { $0.selected }.count
)

The localizedStringWithFormat function is terribly smart.

It will look for a Localizable.stringsdict file before returning and query it for the correct format string to use before returning our final formatted string.

A Localizable.stringsdict is really just a .plist file with a few special strings in it.

We can create a Localizable.stringsdict file either completely by hand in a text editor, or by adding a new Property List to our project and naming it Localizable.stringsdict.

Now that we have a .stringsdict file, let's use it.

The root key is the same one we passed into NSLocalizedString.

Then, we define a sort of string-replacement-variable using some special characters: %#@VARIABLE_NAME_HERE@. The system will then find the sub-dictionary that shares a name with this variable, and use it to pluralize.

We can provide cases for zero, one, two, few, many, and other. Each potential plural case is optional for each language, except other.

Download an example project showing off this functionality here.

Hat tip to Matthew Bischoff for the idea for today's Bite, which actually inspired a whole series of localization Bites with more still to come!

Today we'll continue our series on localizing our apps by looking at NSNumberFormatter.

It can help us make sure we're displaying numbers using the format a user expects in their culture or language, as well as display numbers in some fun ways. Let's get started.

First, let's see how we can take advantage of NSNumberFormatter when localizing our app.

We'll create a new formatter, and tell it to use the user's current locale. (An NSLocale is a class that encapsulates information about linguistic, cultural, and technological conventions and standards).

let formatter = NSNumberFormatter()
formatter.locale = NSLocale.currentLocale()

Now, we can set what kind of format we'd like to perform. NSNumberFormatter has a ton of great built-in styles. Let's try the Currency style:

formatter.numberStyle = .CurrencyStyle
formatter.stringFromNumber(2187.31) // "$2,187.31"

Then, we ask the formatter for a string from a number.

Apple has done all the hard work of figuring out how numbers should change when displayed in different locales. The example before showed the output from a device in the US, what about one from Germany? Let's try it:

formatter.locale = NSLocale(localeIdentifier: "de_DE")
formatter.numberStyle = .CurrencyStyle
formatter.stringFromNumber(2187.31) // "2.187,31 €"

Neat! What else can NSNumberFormatter do? Here's some fun examples:

formatter.numberStyle = .SpellOutStyle
formatter.stringFromNumber(21) // "twenty-one”
formatter.numberStyle = .OrdinalStyle
formatter.stringFromNumber(21) // "21st"

In addition to all of that, NSNumberFormatter also has an insanely long list of customizable properties allowing us to create completely custom formatters (best done via subclassing).

When browsing the App Store, users are likely to scroll right past apps that don't support the language they speak. Like any business, one way we can improve the sales of our apps is to make them useful to new, large groups of people.

Today we'll begin learning about localizing our apps. We'll start by setting up our Xcode project to be localized, then try a simple example using NSLocalizedString.

Let's dive in:

First, we'll head over to our Project's settings **and add a new **Localization language. We'll choose French, then Finish.
This will modify our project (and a few files) to make it localizable.

Next, we'll go to File > New > File… and add a new Strings file called Localizable to help us localize strings in our code.

Yep, it has to be named exactly like that. πŸ˜’

We'll select this new file and head over to the File Inspector panel. We'll click the Localize… button, then the French checkbox.

Now we can edit both versions of our .strings file, adding translate-able strings using a special key/value syntax:

// Localizable.strings (Base)
search-spaceships = "Search spaceships...";
globe = "🌎";
// Localizable.strings (French)
search-spaceships = "Recherche vaisseaux spatiaux...";
globe = "🌍";

Then, we can reference those keys in our code using NSLocalizedString:

searchBar.placeholder = NSLocalizedString("search-spaceships", comment: "Search Placeholder")

We can specify a language to test by editing the Application Language setting of our Scheme's Options.

Success!

Download the example project from this bite right here.

Formatting strings is one of the most common tasks in building software. It's usually not that complex, but it can be tempting to cut corners.

When working with things like currency or street addresses, having a robust formatting system in place can be crucial in ensuring our app works well all over the world.

Today we'll look at Format, a library from Roy Marmelstein that can help us achieve all this with ease.

Format starts by extending Swift's number types to add a format function. We can call this on any number (even literals) and it will return a String with our desired format:

134.format(Decimals.Two) // => "134.00"

Format makes localizing a breeze. It uses the device's current locale by default, or we can render a specific one:

let gb = NSLocale(localeIdentifier: "GB")
87.format(Currency.GBP, locale: gb) // => "Β£ 87.00"

Ordinal numbers can really help class up the joint:

134.format(General.Ordinal) // => "134th"

Format can format in all sorts of interesting ways, for example:

10.11.format(General.SpellOut) // => "ten point one one"

Numbers are cool, but what about addresses? Almost every nation has a slightly different convention for how they format street addresses.

Format wraps CNPostalAddressFormatter from the Contacts framework (Bite #24) to make formatting addresses quite simple:

AddressFormatter().format(
  "1 Infinite Loop", 
  city: "Cupertino", state: "CA", postalCode: "95014", 
  country: "USA", ISOCountryCode: "US")

// => "1 Infinite Loop\nCupertino CA 95014\nUSA"

Format also extends CLPlacemark, adding a function to format that class's addressDictionary property. Users expect things to look familiar. Never underestimate the power of good localization.

More info about Format can be found at git.io/format

NSURLQueryItem is a great little class that joined Foundation in iOS 8. It can help us compose NSURLs in a safer and more predictable way.

iOS and OS X developers have long become familiar with composing URLs in Cocoa. It can be… "interesting" at times.

We've all written a line or two of NSString-concatenation or stringWithFormat code to quickly create a URL. This works in a pinch, but we could easily introduce a bug by putting an & character in the wrong spot, or some other silly typo.

NSURLQueryItem can help! Let's look at how to use it along with NSURLComponents to compose an NSURL:

let components = NSURLComponents()

components.scheme = "https"
components.host = "api.spaceshipapp.com"
components.path = "/ships"

components.queryItems = [
  NSURLQueryItem(name: "start", value: "40"),
  NSURLQueryItem(name: "max_results", value: "20")
]

let requestURL = components.URL

NSURLComponents is quite a useful class on its own that can parse and assemble URLs based on the RFC 3986 standard.

So far we've only created components from scratch, but we could also get the components of an existing NSURL like this:

let components = NSURLComponents(
  URL: NSURL(string: "https://lboc.me?page=2")!,
  resolvingAgainstBaseURL: true
)

This is great for a few reasons. For example, instead of doing something silly like string replacing shudder to change a query parameter, we can instead operate on the components' queryItems array, then export the URL again by calling .URL. Additionally, with this technique, we can now more easily validate query parameters in URLs in our tests! Double-win. Neat!

Thanks to Matthew Bischoff for suggesting today's topic! Send your topic suggestion to hello@littlebitesofcocoa.com

Regular Expressions are a fantastic way to search through text. Apple provides support for them via the NSRegularExpression class. It has great support for matching, extracting, etc. Its API can be a bit verbose for simple matches though. Today we'll look at Regex, a tiny little library from Adam Sharp that makes writing regular expressions in Swift much more friendly and expressive. Let's check it out:

Regex has a bunch of great features, but at its core it allows us to take regular expression code like this:

let stringToMatch = "star wars"

let regex = try! NSRegularExpression(
  pattern: "star (wars|trek)",
  options: NSRegularExpressionOptions(rawValue: 0)
)

let isWarsOrTrek = regex.firstMatchInString(
  stringToMatch,
  options: NSMatchingOptions(rawValue: 0),
  range: NSMakeRange(0, stringToMatch.characters.count)
) != nil

...and turn it into something just a tad more readable:

Regex("star (wars|trek)").matches(stringToMatch)

Regex is backed by NSRegularExpression under the hood, and it does a great job of "swift-ifying" its API. In addition to simple Boolean checks, we can also use Regex in a few other rather Swifty ways. For example, pattern matching:

switch starThing {
case Regex("gate$"): print("dial the gate!")
case Regex("wars$"): print("the force is strong")
case Regex("trek$"): print("set phasers to stun")
default: break
}

Last but not least, we can easily grab any captured strings:

let starRegex = Regex("star( trek| wars|gate)")
if let captured = starRegex.match(inputString)?.captures.first {
  print("You chose: \(captured).")
}

More info about Regex can be found at git.io/regex

Grand Central Dispatch is the name of Apple's collection of task concurrency functions in libdispatch. GCD (as it's often called) is packed full of interesting features involving concurrency, queuing, timers, and more. Let's dive in and take a look at some simple and common use cases:

Common Usage

One of the most common ways to use GCD is to hop to a background queue to do some work, then hop back to the main queue to update the UI:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
  let resizedAvatarImage = self.resizeImage(avatarImage)

  dispatch_async(dispatch_get_main_queue()) {
    self.avatarImageView.image = resizedAvatarImage
  }
}

Dispatch Once

If we wanted to run some code in viewDidAppear: but only wanted it to run the first time, we could store some flag in a Bool property. Or just use GCD:

struct Tokens {
  static var onceToken: dispatch_once_t = 0;
}

dispatch_once(&Tokens.onceToken) {
  self.initSomeState()
}

Dispatch After

We can also easily wait a specified amount of time, then run some code. Here we'll use this technique to pop back to the previous view controller a quick "beat" after the user selects an an option in a table view controller. (As seen in many apps, including Settings.app):

let delay = 0.5
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
  self.navigationController?.popViewControllerAnimated(true)
}
Page 2 of 3