One of the best parts of tvOS is the Top Shelf. It's the bit just above the top row of apps on the home screen that shows previews of each app's content when it's focused (think "Trending Videos", "Recent Photos", etc.).

Today we'll learn how we can provide this same type of functionality in our own apps, by adding a Top Shelf Extension. Let's get started:

We'll add a new target to our app. We'll create a new tvOS > Application Extension > TV Services Extension.

Xcode will generate a ServiceProvider class for us that conforms to the TVTopShelfProvider protocol and provides TVContentItems back to the system.

We'll use .Sectioned for our style so we can provide items like this:

The .Inline style is neat too, but its purpose is only for displaying wide banners like the App Store app.

We'll create a single section item, then set its topShelfItems to an array of items for the things we actually want to display.

var topShelfItems: [TVContentItem] { // ...
  shipsSection.title = "Recent Launches"
  shipsSection.topShelfItems = recentlyLaunchedShips()
    .map { $0.asTVContentItem(sectionID) }
  // ...

We can use TVContentItem's properties to customize/enhance its behavior:

item.title = name
item.imageURL = NSURL(string: "https://spaceshipsapp.com/ships/\(identifier).jpg")
item.imageShape = .HDTV
item.displayURL = NSURL(string: "spaceships://ship/\(identifier)")
item.playURL = NSURL(string: "spaceships://ship/\(identifier)")

There's actually a lot of features packed into this little class: Simple things like separate deep-link URL for selecting, or pressing the Play button on an item, or more advanced functionality like the currentPosition property, which can help us display the user's "watch progress" on our top shelf items.

Download a fully working example project here

In iOS 9, the Contacts framework replaced AddressBook.framework as the suggested way to interact with that data. Today we'll check out a library called EPContactsPicker, which is built on top of the Contacts framework and encapsulates a lot of the boilerplate logic. Let's dive in.

let contactPickerVC = EPContactsPicker(
  delegate: self,
  multiSelection: true,
  subtitleCellType: SubtitleCellValue.Email
)

let nc = UINavigationController(rootViewController: contactPickerVC)
presentViewController(nc, animated: true, completion: nil)

Pretty simple! We can add a delegate function to grab the contact or contacts that were selected:

func epContactPicker(_: EPContactsPicker, didSelectMultipleContacts contacts: [EPContact]) {
  for contact in contacts {
    print("\(contact.displayName())")
  }
}

More info about EPContactsPicker can be found at git.io/contactspicker

Topics

#186: Focus Engine Basics on tvOS πŸ“Ί

Topics

One of the biggest things that sets tvOS apart from iOS is the Focus Engine. Today we'll check out what it does, how it works, and how we can interact with it in our apps. Let's get started.

The Focus Engine is the part of tvOS that manages which view the user is currently focused on in tvOS's interface, as well as moving to another view when the user performs a gesture on their remote (or a game controller).

We get all of this functionality "for free", as long as we're using UIKit controls to construct the UI of our apps.

The Focus Engine will listen for a user's input like a left swipe, then it will look for views that are currently to the left on screen of the currently focused view, and move focus to them.

For many apps, that's really all there is to it. 1.) Construct our UI, 2.) Focus Engine handles it all.

For more advanced usage, there's a few places we can "hook into" and interact with the Focus Engine. Here's some examples:

  • We can update the currently focused view in a similar way to how make layout changes on iOS. First we override the preferredFocusView property on our UIViewController, then we call setNeedsFocusUpdate. (Only works if the view controller already contains the currently focused view).

  • We can have the system ask us if it's ok to make a proposed focus change. For this we'd implement shouldUpdateFocusInContent on our view controllers, answering β€˜yes' or β€˜no'.

  • Lastly, we can use the didUpdateFocusInContext function to (for example) animate our custom views alongside the system's animations.

Weekly Sponsor: Hired 🏒

A continued huge thanks to the folks at Hired.com for sponsoring this week's bites. Finding a good job can be a daunting task. Today we'll take a look at how we can use Hired.com to save our sanity, and find a great job in the process. Let's dive in.

We'll start by entering our email and answering some basic questions:

That's it. Hired will then work with over 3,000 pre-screened companies (both big and small) in 13 major metro areas (North America & Europe) to try find us a great job. Software engineers and designers on Hired can get 5+ job offers in a single week. Each offer will include salary and equity details upfront.

We can view interview requests and accept or reject them before talking to any company. If we get a job through Hired, they'll give us a $1,000 "thank you" bonus!

Even better, if we sign up through this link: littlebitesofcocoa.com/hired, they'll double our bonus to $2,000!

More Reasons to Use Hired

  • Full time or contract opportunities are available
  • View offers and accept or reject them without talking to anyone.
  • Completely FREE + no obligations ever.

Hired is the real deal. They have solved some very real problems and fixed this historically messy process. Looking for a job? Don't waste time, sign up for Hired today so you can get back to work!

.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!

Topics

#184: More Swift Tricks 🎩

Topics

Today we'll continue our look at Swift tips and tricks. Let's dive in.

Nested Types

We'll begin with an organizational tip. We can nest our type declarations inside one another to group related definitions:

enum CostumeDepartment {
  case Day, Night

  struct Color { /* ... */ }
  struct Image { /* ... */ }
  struct Text { /* ... */ }

  func appLogoImage() -> Image { /* ... */ }
}

Swift's compiler is smart enough to take note of this nesting whenever ambiguity arises. This means we can use types nested inside multiple "container" types without any issues.

Even-lazier Lazy Definitions

We covered the lazy keyword in Bite #179. It turns out, we can be even lazier, and omit the extra closure altogether. (Still works the same).

lazy var backgroundView = SpecialBackgroundView()

Variadic Parameters

Objective-C supported these as well, but they were a bit of pain to work with there. In Swift, we simply add an ellipsis (...) to our function's definition, and we receive the arguments as a strongly-typed Swift** array**.

func sum(numbers: Int...) -> Int {  
  var total = 0
  for number in numbers { total += number }
  return total
}

...or if we wanted to write that function in an even Swiftier way:

func sum(numbers: Int...) -> Int { return numbers.reduce(0, combine: +) }

Today we'll continue our localization series with a lesser-known Xcode feature that makes the process of translating our apps easier. Usually we won't be translating our apps ourselves, at least not into all the languages we want to support.

It's common to send our strings off to a third-party service, who will translate them and return them to us. Let's get started.

In Bite #181, we enabled the basic localization features of Xcode. As we work on our app, we'll add new strings:

button.setTitle(
  NSLocalizedString("fly-here", comment: "Fly Here"),
  forState: .Normal)

When we do, we could manually add the new key to all of the different language versions of our Localizable.strings file.

We could also generate a brand new Localizable.strings file using Apple's genstrings command-line tool. Running gentrings *swift in our project's root directory will scan our code and generate a new Localizable.strings file with all the NSLocalizedString keys we've used.

That sounds like it could lead to lots of manual diff'ing.

It turns out that Xcode itself actually has a more powerful feature that can export our strings for translation with almost no manual labor. It pulls from all our Storyboards, .xibs, and scans our code for NSLocalizedStrings.

To use it, we'll select our project at the top of the Project Navigator, and then select Editor > Export for Localization... This will export a folder full of .xliff files for all the languages we've added to our project in Xcode.

This format is standard for most translation services. We'll find a service, then upload these files to them. They'll return us a similar set of files, filled with our translated strings. When they do we'll select Editor > Import Localizations... option then import them back into Xcode.

Popular translation services like Babble-on and Applingua specialize in mobile apps and support .xliff files. We could also edit the files ourselves using a tool like iXLIFF.

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.

Weekly Sponsor: Hired 🏒

A continued huge thanks to the folks at Hired.com for sponsoring this week's bites. Finding a good job can be a daunting task. Today we'll take a look at how we can use Hired.com to save our sanity, and find a great job in the process. Let's dive in.

We'll start by entering our email and answering some basic questions:

That's it. Hired will then work with over 3,000 pre-screened companies (both big and small) in 13 major metro areas (North America & Europe) to try find us a great job. Software engineers and designers on Hired can get 5+ job offers in a single week. Each offer will include salary and equity details upfront.

We can view interview requests and accept or reject them before talking to any company. If we get a job through Hired, they'll give us a $1,000 "thank you" bonus!

Even better, if we sign up through this link: littlebitesofcocoa.com/hired, they'll double our bonus to $2,000!

More Reasons to Use Hired

  • Full time or contract opportunities are available
  • View offers and accept or reject them without talking to anyone.
  • Completely FREE + no obligations ever.

Hired is the real deal. They have solved some very real problems and fixed this historically messy process. Looking for a job? Don't waste time, sign up for Hired today so you can get back to work!

Page 18 of 38