Active Filters: Tools

This time of year it's common to have multiple versions of Xcode installed.

Today we're going to learn how to tell our system which version of Xcode's tools to use when working with Xcode from the command line. But first we'll check out a helpful tool to actually install Xcode from command line.

Let's dive in.

The first tool we'll look at can be used to install Xcode versions directly from the command line. It's an alternative to using the Mac App Store (or just managing downloads manually).

It's called xcode-install and it can be found on Github right here.

We can install it with:

gem install xcode-install`

Once that's finished, we can list the versions of Xcode that are available to install from the command line like this:

xcversion list

Which at the time of this writing will print:

8
8.1
8.2
8.2.1 (installed)
8.3 (installed)
8.3.1
8.3.2
8.3.3 (installed)
9 beta 4

By default, xcode-install only prints the last few major versions.

(Sidenote: For fun and nostalgia try running xcversion list --all to print all the available versions of Xcode going all the way back to 4.3 for OS X Lion 😱).

We can install a version like this:

xcversion install "9 beta 4"

We'll be prompted for our Apple Developer credentials which will be stored in our Keychain, and then the version will be download, installed, and moved into place, all without leaving the command line.

Neat!

More info about xcode-install can be found here on Github.

Next we'll need a way to switch to the new version we just installed.

The tool we'll be working with is already installed on our Mac and is called xcode-select.

It's a straightforward, single-purpose utility that essentially controls which path on disk gets run when we run xcrun, xcodebuild, etc. from our command line.

Let's first check out which version of Xcode we're currently using:

xcode-select --print-path

Which (by default) will print:

/Applications/Xcode.app/Contents/Developer

(Note: This is what's printed for versions of Xcode installed from the App Store).

Next, lets take a look at all of the versions of Xcode we currently have installed.

Here we're going to grep for Xcode inside of our /Applications directory:

ls /Applications | grep Xcode

Which (for example) will print:

Xcode-7.3.1.app
Xcode-8.2.1.app
Xcode-8.app
Xcode-9-beta-4.app
Xcode.app

All we need to do to override the default Xcode path is pass the path of one of these Xcode directories in with the --switch flag:

sudo xcode-select --switch /Applications/Xcode-9-beta-4.app

We'll need the sudo since this xcode-select is working on a system-wide level.

Also, note how we've omitted the /Contents/Developer bit from the path, xcode-select will infer that for us).

Now when we run xcrun, xcodebuild, etc. from our command line we'll be using the Xcode 9 Beta version of each tool.

Nice.

Today we're going to take a look at how we can control (and interact with) the iOS Simulator from the command line.

There's no need to install anything new though. The tool we're going to be using is already on our Mac, hiding inside the xcrun command, which gets installed with Xcode.

It's called simctl.

Let's begin!

First thing we'll want to do is tell simctl to print out a list of our current iOS Simulator devices. We can do that by running:

xcrun simctl list devices

This will print a list of all the simulated devices and a UDID value with each:

-- iOS 10.3 --
iPhone 7 (C4481459-5BB1-4CE1-9BE0-CF0FEA351299) (Booted)
iPhone 7 Plus (ADCB6F99-5ADD-49B1-83AE-5391D845C4D0) (Shutdown)
iPhone SE (FB0899C0-5812-492E-80D9-9DE517554C12) (Shutdown)
iPad Pro (9.7 inch) (45F47977-9A03-4DD1-8FD0-289F7936FE98) (Shutdown)
iPad Pro (10.5-inch) (C3C909DC-BF70-4D67-BF7E-A41A0CF4AF56) (Shutdown)
...

We can see by the (Booted) notation next to the first device that simctl has identified the iOS Simulator we had open at the time of running the command.

We can pass that UDID (C4481459-5BB1-4CE1-9BE0-CF0FEA351299) to other commands to target our currently running iOS Simulator.

For shorthand though, we can also just pass the term booted to target the currently running iOS Simulator.

(Note that in Xcode 9 multiple iOS Simulators can be running at once. If we pass booted in this case, simctl will just choose one for us).

Whew. Ok with that introduction out of the way let's try this thing out.

First up, one of the best features of simctl, opening URLs.

To open a URL in the iOS Simulator, from the command line, all we need to run is:

xcrun simctl openurl booted "https://littlebitesofcocoa.com"

If we look at our iOS Simulator after running that, we'll see Safari open up and load the page.

Neat!

Even better, this works just as well with custom URL schemes:

xcrun simctl openurl booted "spaceships://ships/123"

Very cool.

Next, let's add some photos and videos.

We can use the addmedia subcommand to import media to the iOS Simulator:

xcrun simctl addmedia booted ~/Desktop/images/image1.png ~/Desktop/images/image2.jpg ~/Desktop/images/image3.jpg

We can include one or more file paths here. It supports images, videos, and even Live Photos.

After running, the files will be imported and appear in the Photo Library:

Next: iCloud Syncing.

We can explicitly force a sync of iCloud using this command:

xcrun simctl icloud_sync booted

What's nice about this is we'll even get errors printed if (for example) iCloud isn't yet configured in this simulated device:

An error was encountered processing the command (domain=BRCloudDocsErrorDomain, code=2):
The operation couldn’t be completed.
(BRCloudDocsErrorDomain error 2 - Logged out - iCloud Drive is not configured)

This next one's a doozy. We can use simctl to record and stream live video, and capture screenshots of any screen of our iOS Simulator.

First let's grab a screenshot:

xcrun simctl io booted screenshot ~/Desktop/screenshot.png

Neat. Easy enough, next let's try recording a movie:

xcrun simctl io booted recordVideo --type=mp4 ~/Desktop/movie.mp4

Full quality movie file is available here, for the curious.

The recordVideo subcommand's output can be | (piped) into other commands or even to a TCP or UDP socket for live streaming. This works on all iOS, tvOS, and even watchOS Simulators. Very cool.

Last but not least, we can print out the path for app's installation directory on disk:

xcrun simctl get_app_container booted com.spaceships.app
/Users/example/Library/Developer/CoreSimulator/Devices/C4481459-5BB1-4CE1-9BE0-CF0FEA351299/data/Containers/Bundle/Application/49A59051-1404-431C-8B65-B589EC0F6267/Spaceships.app

Nice.

To save us a step, we can | (pipe) that path output to pbcopy to put the value on our clipboard for easy pasting later:

xcrun simctl get_app_container booted com.spaceships.app | pbcopy

There's plenty more that simctl can do. To see the long list of available commands and features, we can run:

xcrun simctl

We can add, remove and even reset/erase simulated devices, interact with a device's pasteboards, launch apps with environment variables and much more.

That's all for now, happy simulating!

-- Update: Tuesday July 25th, 2017 --

Friend of the pod Bites? (and creator of the fantastic Fastlane suite of tools, (Bites)) Felix Krause writes in with a great addition regarding the --json flag:

We can pass the --json (-j for shorthand) flag to any of the simctl commands that print information to print it in JSON format.

This is perfect for | (pipe)-ing to other commands, or for consumption by a host process/program:

xcrun simctl list runtimes --json
{
  "runtimes" : [
    {
      "buildversion" : "14E8301",
      "availability" : "(available)",
      "name" : "iOS 10.3",
      "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-10-3",
      "version" : "10.3.1"
    },
    {
      "buildversion" : "14V243",
      "availability" : "(available)",
      "name" : "watchOS 3.2",
      "identifier" : "com.apple.CoreSimulator.SimRuntime.watchOS-3-2",
      "version" : "3.2"
    }
  ]
}

Topics

#297: Simulating HomeKit Accessories 💡🤖

Topics

"Home automation" is perhaps one of the hottest topics in technology these days.

While still an emerging market, many iOS device owners now also own at least one or two "smart home" devices.

Today we'll begin looking at HomeKit, Apple's framework for communicating with and controllling these devices from inside our apps.

Before we can dive in though, there's a bit of tooling we need to learn about first. Specifically, we need to learn how to simulate HomeKit devices.

For example, we might not own any HomeKit devices ourselves. Even if we do though, we'd rather not need to phsyically change things about our home to test our app.

Not to worry, Apple provides a great solution to this challenge in the form of a HomeKit Accessory Simulator app for macOS.

In it, we can setup and configure a "simulated" set of devices in any kind of Home setup we'd like.

Sadly though, it doesn't ship with Xcode.

We'll need to head over to Apple's "More Developer Downloads" page here and search for "Hardware IO Tools for Xcode". We'll download the latest release, then install the HomeKit Accessory Simulator app.

Now, let's open it up and simulate our first accessory.

We'll click the + button in the bottom left and select New Accessory...

We'll fill out the fields with some example information. The values aren't super important, they merely need to be unique and somewhat realistic.

Neat. We've now got a (pretend) lamp. 💡

Well, sort of. There's actually one more important step, and it's speaks to the heart of how HomeKit works.

So far, HomeKit doesn't know anything about our new lamp. "Lamp" is just the name we gave it.

For HomeKit to do something useful with our device, we'll need to add a HomeKit Service to it. HomeKit Services describe the capabilities and functionality of a device

We'll click the Add Service... button on our new device, and choose Lightbulb from the dropdown menu.

We can leave the rest of the fields alone.

Neat! Not only do we now have a fully-simluted, color changing light bulb, we're also provided with some nice sliders and controls to read from, and write to, the current state of the device.

That's all for today. We'll learn more about the HomeKit Accessory Simulator as we continue to explore HomeKit. Next time we'll learn how to change this light's color in code! 🌈💡

Topics

#292: Metaprogramming with Sourcery 🔮

Topics

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

Topics

#284: More Xcode Source Editor Extensions 🤖🛠

Topics

Today we'll dive back into the world of Xcode Source Editor Extensions (Bite #239). These extensions can not only help us save time and effort, they're also a great way to customize Xcode to our exact needs. Let's dive in! 🏊

First up, Cleaner Closures. We can use CleanClosureXcode from Patrick Balestra to clean up all those unnecessary ('s and )'s from our Swift closure definitions:

Beautiful. No more manually arrow-key-ing around to get rid of those.

Next, let's look at a common feature of many IDEs and text editors: the ability to "jump" the cursor multiple lines up or down. Xcode can't really do that... until now. Thanks to Jump, we're given a few new menu items in our Editor menu to move the cursor up or down by 2 or 5 lines. Neat.

Pro Tip: We can use the Key Bindings tab of Xcode's Preferences window to customize the keyboard shortcuts for each of these movement commands (or any other commands).

Finally, let's check out QuickAdd from Sidney de Koning.

This extension allows us to select some text, and then insert a new function definition into our code, complete with documentation comment, and placeholders we can press tab to jump between.

This allows us to employ a workflow of:

1.) Call a function that doesn't yet exist when writing some code as a sort of "placeholder".
2.) When we're done with that chunk of work, select the name portion of the function call and press a keyboard shortcut to "generate" the function and insert it into our file.
3.) Profit!

Full installation instructions are here.

Know of another neat Source Editor Extension? Send it along!

Topics

#283: Generating Models from JSON with json2swift ⚒

Topics

Integrating our apps with HTTP APIs often involves a fair amount of "busy work". Writing models to match API responses, manually iterating each field in a JSON object, and typing each in as a Swift property can be a bummer. Today we'll check out a great new tool from Josh Smith called json2swift that can help us here. It can generate Swift model code from a JSON object. Let's give it a try.

After we've installed json2swift, we can run it like this:

json2swift Spaceship.json

This will create a new file called Spaceship.swift in the same directory as our .json.

This means if our Spaceship.json file looked like this:

{
  "name": "Tantive IV",
  "topSpeed": 950
}

The resulting json2swift-generated Swift model would look like this:

struct RootType: CreatableFromJSON {
  let name: String
  let topSpeed: Int
}

Neat!

json2swift has generated an immutable Swift struct from our JSON file. Pro Tip: We can also run this on a directory full of JSON files, and it will process all of them.

json2swift will even try to determine which properties should be optional, and which are required. It will then generate the appropriate init code.

We're even provided some special handling for things like Date parsing. If we put a special String like this in our original JSON:

{
  "name" : "Tantive IV".
  "buildDate" : "DATE_FORMAT=yyyy-MM-dd"
}

This will give us a:

let buildDate: Date

property, as well as generate the appropriate Date format/parsing code needed to make it work. Neat!

We've only scratched the surface, json2swift has great support for intelligenty inferring types for things like numbers, and even URLs. Learn more about json2swift at git.io/json2swift.

Topics

#278: Saving Time With Source Editor Extensions 🤖🛠

Topics

We touched briefly on this topic back in Bite #273 with Generating Initializers. Today we'll take a look at a few additional Xcode Source Editor Extensions (Bite #239) that can help us save time while working. Let's begin.

First up, Equatables. We can use XcodeEquatableGenerator from Serg Dort to quickly generate the long list of property comparisons often required when adopting the Equatable protocol in our Swift Structs or Classes:

Whew! That used to take ages! Full installation instructions are here.

Next, Localization. We've all been on a project with no localization. Adding that first round of NSLocalizedString() calls can be a pain. No longer! Now we can use Localizer from Esteban Torres.

With it, we can select a line of code like this:

let _ = "Mission Control Panel"

Then, when we run Localizer's command, this line becomes:

let _ = NSLocalizedString("Mission Control Panel", comment: "Mission Control Panel")

Neat! Learn more about Localizer here.

Last but definitely not least, is XcodeWay by Khoa Pham. This one is a bit different in that it doesn't modify or generate any code, but rather lets us quickly open a bunch of commonly used directories, by adding them to our Editor Menu:

Nice! No more hunting around in Finder or Terminal for these.

Know of another neat Source Editor Extension? Send it along!

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

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

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.

Page 1 of 6