Active Filters: Tools

Topics

#133: Code Coverage in Xcode ๐Ÿ› 

Topics

Code Coverage arrived with Xcode 7. It can help us visualize which parts of our code are not being tested enough (or at all). Let's dive in:

Before we can take advantage of Code Coverage, we'll need to enable it for our project. It's off by default.

We'll begin by editing our scheme, then selecting Test in the sidebar, then enabling the Gather coverage data checkbox.

Now we'll run our tests by going to Product > Test in the menu (or pressing U). Then we can check out the test log where we'll find a new โ€œCoverageโ€ tab.

Xcode will display all the functions in our code with a bar graph indicating how well โ€œcoveredโ€ they are by our tests (We can mouse over to get an exact percentage). In our case, we are at 0%, since we don't have any tests. Yikes! Let's fix that by adding a simple test for a function on our PersonViewModel:

func testFullName() {
  let person = Person(firstName: "Han", lastName: "Solo")
  let personVM = PersonViewModel(person: person)
  XCTAssertEqual(personVM.fullName, "Han Solo")
}

If we run our tests again, and check the Coverage tab, we can see we now have 50% test coverage for our tiny example project.

Last but not least, Xcode will also give us a heads up with a red shaded area in the right gutter on lines of code that aren't covered by our tests. Neat!

Topics

#129: More UI Testing Tips ๐Ÿšธ

Topics

Today we'll look at a couple more tips to get the most out of UI Testing in Xcode. (Covered previously in Bites #30, and #124).

Are We in a Test?

It'd be great if our app could know when it's running inside of a UI Test, then behave differently. We'll start by setting a flag that we can check for later. We'll add a launchArgument before we launch our app in our tests' setUp functions.

let app = XCUIApplication()
app.launchArguments = [ "IS_UI_TESTING" ]
app.launch()

Then, we'll add a new helper function to our app's code. We could add this to a helper class, or just make it a global function:

func isUITesting() -> Bool {
  return Process.arguments.contains("IS_UI_TESTING")
}

We can use this function throughout our code to do things like hit mock servers during testing, or simulate a camera preview when capturing screenshots with snapshot. (Bite #110).

Dismissing System Alerts

We have to jump through a couple of hoops here. First we'll need to set up what's called a "UI Interruption handler", which will execute a closure when the UI is interrupted by, for example, an alert being shown:

addUIInterruptionMonitorWithDescription("Authorization Prompt") {
  $0.buttons["Allow"].tap()
  return true
}

app.tap()

Then, after our app presents the authorization prompt, we'll need to .tap() on it once before the UI Interruption handler will fire. Inside our handler, we'll accept the prompt then return true to tell Xcode we've handled the UI interruption.

Have a UI Testing tip or trick of your own you'd like share? Send it along to hello@littlebitesofcocoa.com!

Today we're continuing our look at the Fastlane suite of tools with gym. It can help us build and package our app into an .ipa file ready for submission to Apple, or some other kind of distribution. Let's get started.

We'll start by installing gym:

gem install gym

Now we can build and export an ipa like this:

gym

Alright, have a great weekend everyone! Just kidding, while gym is great about asking for answers to things we don't specify such as what Xcode Scheme to use when building. It also allows us to specify just about any option we can imagine when running it on the command line. For example, let's build our app using its Workspace and the app-store scheme:

gym --workspace "Spaceships.xcworkspace" --scheme "app-store" --clean

Simple enough, we're telling gym to build using our desired Workspace and Scheme, and that we'd like to do a clean build.

gym has options for just about everything: bitcode, codesigning, provisioning, team id, and much more. It's extremely flexible but including all those command line options each time can be drag. Let's unlock more of the power of gym by creating what's called a Gymfile in our project's directory. This is just a plain text file, and looks like this:

scheme "Spaceships"
sdk "iphoneos9.0"
clean true

output_directory "./build" # where to put the ipa
output_name "Spaceships"   # what to call the ipa

Now we can run gym again from the command line and we don't need to specify all those options each time, nice! More info about gym can be found at git.io/gym

Topics

#124: More on UI Testing ๐Ÿšธ

Topics

We covered the basics of UI Testing in Xcode when it was first announced all the way back in Bite #30. It's a fantastic way to test our app's interface. Today we'll look at a few more UI Testing odds and ends. Let's dive in:

First, let's write a test to verify that one of our table views properly loads and displays its data. The data is loaded asynchronously (which should be mocked in our test, but that's a future Bite). We'll need to give our app a little time to load and render the data we're testing for. We can use an expectation to easily pull this off:

expectationForPredicate(
  NSPredicate(format: "count > 0"),
  evaluatedWithObject: app.tables.cells,
  handler: nil)

waitForExpectationsWithTimeout(5, handler: nil)
XCTAssertGreaterThan(app.tables.cells.count, 0)

Xcode will wait up to 5 seconds for the predicate we've passed in to be true (for there to be more than 0 cells in our table). After that the XCTAssert will be executed and evaluated.

We can change the simulated orientation of the device like this:

XCUIDevice.sharedDevice().orientation = .LandscapeLeft

Quite helpful for testing all that great new Adaptive UI code!

Finally, let's look at performing some interactions beyond simple taps. We can do things like long press an element:

app.buttons["+"].pressForDuration(0.5)

or perform simple pans using the convenience swipe functions:

app.tables["Crew"].swipeDown()

We can even execute more complex pan gestures using the pressForDuration(duration:thenDragToCoordinate:) function:

  let point = table.coordinateWithNormalizedOffset(CGVectorMake(0, 2)
  table.pressForDuration(0.5, thenDragToCoordinate: point)

It's another Fastlane Friday here on LBOC. Today we're looking at deliver, another awesome tool in the Fastlane suite. It can save us tons of time and effort when it comes to uploading our app's metadata, screenshots and binary to iTunes Connect. Let's take it for a spin:

We'll start by installing deliver:

gem install deliver

Then we'll setup deliver for our project by cd'ing into its directory and running:

deliver init

We'll be asked for our iTunes Connect login and then our app's App ID. What happens next it down-right magical .

deliver will download all our app's metadata (name, description, keywords, release notes, icons, etc.), by language, from iTunes Connect as text files. Then it will organize them into text files inside a new metadata directory. Now we can edit these anytime and run deliver to update iTunes Connect with the edited values. Nice!

In addition to our app's metdata, deliver will also download all our app's screenshots (by language and device) and organize them into a new screenshots directory for us. Again, we can change/update them on disk then simply run deliver again and they'll be uploaded to iTunes Connect.

It gets better. Why don't we just do everything at once and update our app's metadata and screenshots, upload its binary and submit it for review all at once? With deliver, all it takes is:

deliver --ipa "Spaceships.ipa" --submit_for_review

Believe it or not, deliver can do even more. We can pass in tons of options for configuring things like automatic release vs. manual, price tiers, add pre-defined answers to all those compliance questions we're asked during submissions, and more. We can also create a Deliverfile to easily reuse our options every time.

More info about deliver can be found at git.io/fastlane-deliver

Topics

#114: Creating New Apps with Produce ๐Ÿ“

Topics

Starting new projects can be incredibly fun. Performing all the tasks that aren't building our app can be incredibly not-so-fun. Today we'll continue our look at the Fastlane suite of tools (from Bite #110) by checking out Produce, a command-line tool for creating and managing apps on iTunes Connect and the Developer Portal. Let's take a look.

Let's make a new app. Before we do though, we'll install produce:

gem install produce

Now, let's create our app, we'll run:

produce

Then we'll be asked for 4 values. We'll enter each when prompted (We could also specify these as arguments to the produce command).

Your Apple ID Username: **hidden**
App Identifier (Bundle ID): com.magnus.littlebitesofcocoa
App Name: Little Bites of Cocoa
Initial version number (e.g. '1.0'): 1.0

Produce will work its magic and when it's done, our app will have been completely created and setup on both iTunes Connect and the Developer Portal. Very cool.

Capabilities

Produce can also help us easily enable (or disable) things like Associated Domains, iCloud, Passbook, etc. Let's enable CloudKit for our app:

produce enable_services --icloud cloudkit -a com.magnus.littlebitesofcocoa

Nice! So much quicker than clicking around the Developer Portal.

App Groups

Last but not least, we'll be creating extensions for app that share data so let's create a new App Group and put our new app into it:

produce group -g group.littlebitesofcocoa -n "Little Bites of Cocoa"
produce associate_group -a com.magnus.littlebitesofcocoa group.littlebitesofcocoa

More info about Produce can be found at git.io/produce

We covered how to analyze the performance of our app using the Time Profiler Instrument in Bite #68, now we'll take a look at how to do the same for how quickly our app draws its content to the device's display. Let's get started.

First, the basics: iOS wants to render content to the display 60 times per second. If our code can't keep up with that speed, some frames won't be drawn, and our app's UI will appear to lag and "skip" as things move around on screen. Even the slightest dip below 60 frames per second can make an app feel quite sluggish. One of the main places in our code this can be a challenge is when scrolling complex table and collection views. Let's look at how Instruments can help us identify and track down the cause of slow rendering views in our app:

We'll start Profiling like in Bite #68. When Instruments launches, we'll select the Core Animation Instrument and click Profile. Unlike before, we'll see two different gauges at the top of our screen.

We're starting to unlock some of the power of Instruments here. The Core Animation Instrument measures our app's rendering performance simultaneously with our code's performance. We'll scroll our table view for a bit then find a part of the graph where we dip below 60 fps. We'll drag to select it, then select the Time Profiler gauge. Now we can use the techniques we learned in Bite #68 to track down the offending slow function(s).

Now the really fun stuff: We can click the in the lower right-hand sidebar to show the Debug Options panel. These options alter how our app is drawn in real-time to help find problems. Here's a couple of the most helpful ones:

Color Blended Layers will tint views red that are being blended. Try to avoid non-opaque views or views with a clear background color.

Color Offscreen-Rendered Yellow will tint views that have been rendered twice - once on and once off-screen, yellow.

Remember, speed is a feature. Rendering speed is no different. Fast drawing means happy users!

Topics

#110: Snapshot ๐Ÿ“ธ

Topics

Fastlane is collection of incredibly helpful tools built by Felix Krause.

This week, Twitter announced that Fastlane would be joining their already-great Fabric suite of tools. Congrats Felix! ๐ŸŽ‰

We'll be taking a look at some of Fastlane's tools individually in the coming weeks. Today we'll begin with snapshot.

If we're being good localization citizens in our apps, we could have something like 20 or more languages that we support. We also want to market our app well, so we use all 5 screenshot slots on the App Store. Oh, and we support lots of different iOS devices. Ack!

This all adds up to potentially hundreds of new screenshots to capture and upload each release. We better make sure we get the status bar looking clean, and not accidentally capture any loading snippers, etc. Eesh. That sounds like a whole lot of time spent not building apps. Let's see how we can use snapshot to save our sanity:

snapshot uses Xcode 7's UI Testing functionality (Bite #30) to help us automate our apps and specify exactly when to capture screenshots. It also makes sure they look great with presentable status bars, etc.

Let's use the springboard app we created in Bite #104 to try it out.

We'll install the snapshot gem, then head into our app's main directory and run snapshot init.

This will create a SnapshotHelper.swift file we'll need to add to the UI Test target in our project.

Instead of calling launch on XCUIApplication() directly, we need to plug snapshot into the mix by calling setLanguage on our app, then launching it. In our test, we'll snap a screenshot of the initial screen and give it a name.

class SnapshotTests: XCTestCase {
  override func setUp() {
    super.setUp()

    continueAfterFailure = false

    let app = XCUIApplication()
    setLanguage(app)
    app.launch()
  }

  func testExample() {
    snapshot("01MainScreen")
  }
}

Now we just head into our app's directory and run snapshot.

Our screenshots will be captured, and saved to disk. We can check out the results in Finder.

To configure the list of devices and languages that will be captured we can add the Snapfile that was created earlier when we ran snapshot init to our project as well and customize it to our needs.

More info about snapshot can be found at git.io/snapshot.

Topics

#109: Xcode Code Snippets ๐Ÿฐ

Topics

Today we're talking Code Snippets. These are a great way to speed up our workflow. A well-kept library of snippets can save us hours of writing repetitive boilerplate code. Let's take a look.

We'll begin by opening the Utilities sidebar by clicking the button on the far right of the toolbar. Then we'll click the curly braces { } icon in the bottom panel to see our library of snippets.

Xcode ships with a decent starting set of snippets, but the real power comes when we start to define our own. Let's make a snippet for something we do all the time: Hopping to a background queue, then hopping back to the main queue to update some UI.

We'll start by writing some code we want to make a snippet. We can put this anywhere, we'll delete it when we're done:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
  // background code

  dispatch_async(dispatch_get_main_queue()) {
    // main queue code
  }
}

Next, we'll replace those comments with some tokens. When we use our snippet, we'll be able to press the tab key to cycle through each token and easily replace it. Tokens are defined like this:

<# token name #>

We'll replace our two comments with tokens, then select our whole snippet and drag and drop the code itself onto our library of snippets. A panel will open, where we'll be able to describe our snippet, and configure when it can be triggered.

We'll use hop for our completion shortcut, then click Done, to try it out. Beginning to type hop and pressing tab now inserts our code. Success!

Topics

#100: Just Getting Started ๐Ÿš€

Topics

At one point or another, we've all heard some form of "Oh you make apps? I'm interested in that, but I'm having trouble just getting started". Today we'll take a look at the specific steps to create our first app and where to go from there. Let's dive in:

We'll need a Mac. We'll open the Mac App Store and search for "Xcode", then install it. (It's free).

Once it's installed, we'll open Xcode. We'll allow it to verify it's installation, and install any components it needs to.

Then we'll go to the File menu and choose File > New > Projectโ€ฆ We'll leave the Master-Detail iOS Application selected and click Next. We'll give our new app a name: "Foodstagram". We'll enter "com.somename" as the organization identifier, select Swift as the language, and click Next. Finally, we'll choose where to save our new project, then click Create.

When our project opens, we'll hit the little โ–ถ button in the top left corner. Xcode will build our new app and launch it in the Simulator.

Hey it's an app! Hit the + button to add some entries, then edit to delete them.

Congratulations, our new app-venture (sorry, had to) has begun! Next, we need to learn how to learn. When first starting out, much of our time will be spent Googling for things we don't know yet. This is completely normal. Let's start right now.

We'll look at going from idea to implementation. Our idea: "The top bar of the app should be green."

We'll Google for how to do it, using as specific a phrase as we can given what we know so far:

"ios swift change top bar background color".

We'll read the first result from stackoverflow. The first answer contains some possibly helpful code snippets, but we'll read a few more to be sure. It seems the rest of the answers all suggest a similar piece of code talking about "appearance". Sounds promising. One even mentions "color" and "green", so we'll copy it for pasting later:

UINavigationBar.appearance().barTintColor = UIColor.greenColor()

Where do we even put this code? Back to Google.

We'll keep reading our search results until we find a coderwall post from Eranga Bandara that answers our question: "Add following code to didFinishLaunchingWithOptions function in AppDelegate.swift".

Perfect, we'll do just that and click the AppDelegate file in Xcode, then paste our copied code at the end of the specified function.

We can check if it worked by clicking the โ–ถ button again. Success! Our top bar is now green!

We can't learn everything this way, so our next step is to try to find something to teach us the rest of the basics. There's plenty of great resources out there, including one that's just getting started. ๐Ÿ˜‰๐Ÿซ

Page 4 of 6