It's another fastlane Friday! Today we're looking at frameit, an awesome fastlane tool that helps us take our screenshots to the next level. We can display our screenshots on devices, and even add some marketing text. Let's dive in.

We'll start by installing frameit:

gem install frameit

Next we'll need to perform some initial setup. We'll head into our project's directory and run frameit to kick things off:

frameit will guide us through downloading the high quality frame images from Apple's marketing site and moving them into place.

Now, we can run frameit anytime to find all screenshot files and create versions of them placed inside device frames. Neat!

This works great after running snapshot (covered in Bite #110).

As with most fastlane tools, we can create a Framefile.json where we can configure things like texts, fonts, etc. frameit even lets us use .strings files so everything is easily localized!

frameit also supports all of this for OS X apps as well!

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

Topics

#154: Return of the UIKit B-sides! 📼

Topics

Today we're continuing our look at lesser-known UIKit features. Let's get started:

Fixing Unwanted Undo Prompts

Ever been testing an app and have an unwanted "Undo" prompt appear? This can be dynamically enabled or disabled with a property on UIApplication:

UIApplication.sharedApplication()
  .applicationSupportsShakeToEdit = false

Customizing Tab Bar Items Layout

We can use the UITabBar's itemPositioning property to control whether tab bar items use a "fill" or "centered" layout:

let tabBarController = UITabBarController()
tabBarController.tabBar.itemPositioning = .Centered

Significant Time Changes

The applicationSignificantTimeChange app delegate function lets us know when things like daylight savings time begin.

Refresh Control Labels

UIRefreshControl has an attributedTitle property we can use to show a nice little bit of text when a user pulls to refresh:

refreshControl.attributedTitle = attributedStringForRefreshControl()

In-App Dictionary View Controller

This one is awesome.

We can use a reference library view controller to display a nicely formatted screen depicting the definition of a term in our app. Neat!

let vc = UIReferenceLibraryViewController(term: "awesome")
showViewController(vc, sender: nil)

In Bite #147 we looked at installing Xcode Plugins using the Alcatraz Package Manager. Today we'll look at a few plugins we can install that will make the experience of writing code in Xcode much better. Let's get started.

First up is Fuzzy Autocomplete. In Bite #146, we covered using Xcode's "Quick Open" dialog. It has this great "fuzzy matching" feature where (for example) we can type something like "upvc" and it will match UserProfileViewController.swift. This plugin brings that exact same functionality to Xcode's autocomplete:

Next, a simple one. Normally when we press ⌘← in Xcode, it jumps all the way to the very beginning of the line. The Xcode Beginning of Line plugin alters this, and instead jumps to the first character of code. Neat!

The QuickJump plugin is super fun. We can activate it with a keyboard shortcut, then it will display a bunch of characters, we type the one where we want our cursor to move and we're there!

Refactorator let us rename functions, vars, enums etc. in Swift!

Finally, with the KSImageNamed plugin, Xcode will autocomplete names of images, when calling functions like UIImage(named:):

All of the plugins mentioned here are available in Alcatraz.

We're continuing our look at lesser-known UIKit functionality today with UITableView & UITableViewCell. Let's see what we can find:

Blur & Vibrancy Visual Effects

We can set UIVisualEffectView backgroundView, and a vibrancy separatorEffect so our table view really shines:

let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .Dark))

tableView.backgroundView = blurView
tableView.separatorEffect = UIVibrancyEffect(forBlurEffect: blurView.effect as! UIBlurEffect)

Row Actions

We can get those awesome "swipe-to-reveal" actions from Mail.app in our own table views. We just need to implement one delegate function and return an array of UITableViewRowActions.

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
  let deployAction = UITableViewRowAction(
    style: .Default,
    title: "Deploy"
  ) { (action, indexPath) in
    // TODO: Deploy the troop at this indexPath.row
  }

  return [deployAction]
}

Adjusting to State Transitions

We can override the willTransitionToState(state:) and didTransitionToState(state:) functions in our UITableViewCell subclasses to run code when the cell begins or finishes showing the edit control or delete confirmation:

class StormtrooperCell : UITableViewCell {
  override func didTransitionToState(state: UITableViewCellStateMask) {
    super.didTransitionToState(state)

    if state == .ShowingEditControlMask { print("began editing!") }
  }
}

Multiple Selection Background View

We can set a special background view on cells that will be shown only when we our table view supports multiple selection:

multipleSelectionBackgroundView = EditingView()

Topics

#151: UIView B-sides 📼

Topics

Today we'll begin looking at some lesser-known functionality inside UIKit. Some of these may be old news, but hopefully not all are.

We'll start with UIView. Let's flip it over and see what kind of b-side treasures we can find:

Subview Callbacks

We can override functions like didAddSubview(subview:) and willRemoveSubview(subview:) in our UIView subclasses. With this, we can take some action when subviews are added/removed.

class ContainerView : UIView {
  override func didAddSubview(subview: UIView) {
    super.didAddSubview(subview)

    subview.frame = calculateFrame(subview)
  }
}

Resigning First Responder

An oldie, but a goodie. We can use the endEditing(force:) function to ask (or force) a view or any text fields inside it to resign as the first responder:

view.endEditing(true)

Custom Layer Class

We can specify a custom CALayer subclass for our UIView subclasses by overriding the layerClass function. This is great if our view needs to use CATiledLayer to scroll lots of content, or when building a camera preview view:

class CameraPreviewView : UIView {
  override class func layerClass() -> AnyClass {
    return AVCaptureVideoPreviewLayer.self
  }
}

Easy Masking

We can "mask" a view using the alpha channel of another view by setting it to the maskView property:

view.backgroundColor = UIColor.redColor()
view.maskView = UIImageView(image: UIImage(named: "vader"))

Weekly Sponsor: Buddybuild 🤖🛠

Incredibly excited to welcome a brand new sponsor: Buddybuild! Buddybuild is the simplest and fastest way to automate our iOS continuous integration and continuous deployment workflows (and much, much more). Let's take a look:

Buddybuild ties together and automates: building, testing, deploying and gathering feedback for our apps. Let's try it.

We'll sign in with Github, and Buddybuild will ask us to choose the repository that contains the app we want to use with Buddybuild.

Next, Buddybuild will pull down our code and look for apps and schemes in our repo, and begin to build our app. We don't have to configure anything or write any scripts, Buddybuild takes care of everything automatically. 🤖

Buddybuild will now build and run our tests each time we push to Github, and we still haven't configured a thing by hand, neat!

Let's continue by importing our certificates and profiles. Buddybuild provides a simple way to do this. We just need to copy/paste and run the command they provide, and all the right files will be securely uploaded. 🔒

Next, we can invite testers, and they can register on their devices. We can even connect our iTunes Connect accounts so we never have to manage new devices, UDIDs, profiles or signing identities again. New testers and their devices will be automatically provisioned on our behalf!

Now, we can now instantly deploy to testers on every build, every night, or on demand.

Testers can provide feedback by taking a screenshot. Buddybuild will kick in and show them a slick custom UI for graphically annotating and sending feedback notes. We'll also get reports of any crashes with the exact line they occurred on.

Last but not least, Buddybuild integrates with tons of services like GitHub, BitBucket, GitLab, Slack, JIRA, Pivotal Tracker, Slack, HipChat, and more.

Buddybuild is an incredible tool that's absolutely packed with great features, try it right now with your own apps at buddybuild.com!

Way back in Bite #93 we talked about creating a "router" for Alamofire that would generate URL requests from enum cases.

In most apps we'll likely end up with some version of that code to help communicate with the API for that particular app. It'd be great if there was some sort of "standard" way to write this code each time.

Today we'll look at a library called Moya that aims to provide this. Let's dive in. 🏊

Moya is a network abstraction layer that encapsulates calling Alamofire functions. It helps us avoid creating messy custom network abstractions in every project.

To use Moya in an app, we'll need an enum with a case representing each API endpoint we want to hit:

enum FirstOrder { case AllTroops; case Troop(String) }

Then we'll extend it to conform to Moya's TargetType protocol:

extension FirstOrder: TargetType {
  var baseURL: NSURL {
    return NSURL(string: "https://api.firstorder.galaxy.far.away")!
  }

  var path: String {
    switch self {
    case .AllTroops: return "/troops"
    case .Troop(let id): return "/troops/\(id)"
    }
  }

  var method: Moya.Method { return .GET }

  var parameters: [String: AnyObject]? {
    switch self {
    case .AllTroops: return ["sort": "recent"]
    default: return nil
    }
  }

  var sampleData: NSData {
    switch self {
    case .AllTroops:
      return "[{\"id\": \"FN-2187\"}]".dataUsingEncoding(NSUTF8StringEncoding)!
    case .Troop(let id):
      return "{\"id\": \"\(id)\"}".dataUsingEncoding(NSUTF8StringEncoding)!
    }
  }
}

Finally, we'll create a new Moya provider using our enum and make it available globally:

let FirstOrderAPI = MoyaProvider<FirstOrder>()

Now we can make requests like this:

FirstOrderAPI.request(.Troop("FN-2187")) { result in
  switch result {
  case .Success(let response):
    do {
      let json = try response.mapJSON()
      // TODO: Parse JSON
    } catch(let error) { handleError(error) }
  case .Failure(let error): handleError(error)
  }
}

This is just a taste, Moya has a ton to offer including some fantastic enforcement of good testing practices.

In conforming to the TargetType protocol, we're actually required to provde sampleData. We can also customize things further by providing an endpointClosure when creating our provider.

More info about Moya can be found at git.io/moya

Style is important when writing code. Following conventions and guidelines helps tell the story of our code to our team and our future-selves. Today we'll learn about SwiftLint, a tool from Realm that can help us enforce Swift conventions and best practices. Let's get started.

SwiftLint provides a downloadable install package on its Github page, but here we'll install using Homebrew. We'll run:

brew install swiftlint

Now, we can run swiftlint rules at the command line to see all the different convetions and standards that will be enforced. We can also run swiftlint lint in the root directory of our project to see what rules we're breaking right in the terminal.

Our next step is to add SwiftLint as a build phase to our project.

We'll head over to our project's settings, then to the Build Phases tab. We'll click the + button to add a** new “Run Script” phase**. We'll name it “SwiftLint” and give it the follow script content:

if which swiftlint > /dev/null; then
  swiftlint
else
  echo “Download SwiftLint: https://github.com/realm/SwiftLint"
fi

Now when we build our project, SwiftLint will let us know via regular Errors and Warnings in Xcode when there's something to fix.

We can configure how SwiftLint behaves in complete detail by creating a new file called .swiftlint.yml and putting it in the root directory of our project. We can fill out this file to customize (for example) which conventions are enforced:

disabled_rules:
  - colon
  - control_statement

We can disable rules “in-line” in our code with special comments:

// swiftlint:disable colon
let noWarning :String = "" // No warning about colon placement
// swiftlint:enable colon
let yesWarning :String = "" // Warning generated

Finally, SwiftLint can correct some violations (trailing_newline, trailing_semicolon, etc.). Just run swiftlint autocorrect.

More info about SwiftLint can be found at git.io/swiftlint

Topics

#148: Using Behaviors to Automate Xcode 🤖🛠

Topics

Today we'll look at Behaviors in Xcode. Behaviors are a way for us to tell Xcode “whenever this specific thing happens, I want this other specific thing (or set of things) to happen automatically.” Let's get started.

We'll start by opening Xcode's preferences (Xcode > Preferences) or ⌘, and heading to the Behaviors tab:

In the sidebar on the left we'll find a list of events that can occur in Xcode. We can trigger something to happen off of any of these events.

On the right of the Behaviors tab, we can choose what actions we'd like triggered when the selected event occurs. We can select as many of these as we'd like and they'll all happen, like magic 🎩, each time the selected event occurs.

Let's start simple and play a sound each time a build fails. We'll select the appropriate item in the sidebar, then enable the “Play sound” checkbox.

Xcode uses Behaviors itself. For example, when an error is found, it shows the issue navigator. When our app finishes building, it shows the familiar “Build Succeeded” bezel. When our apps begins running it shows the debugger. (All things that, since we now know about Behaviors, we can customize).

There's a ton of power packed into Behaviors, and it's all quite simple to configure. We can hide/show different panels, jump to specific spots in Xcode's interface, even run a custom script. Try to examine the little things you find yourself doing in Xcode (hiding a panel, going over to the build log, etc.) maybe a Behavior could save you the trouble!

Xcode is an incredible piece of software with tons of great features. There's always room for improvement, though. Today we'll look at Alcatraz.

It's a plugin for Xcode that lets us install other plugins for Xcode. (Also themes and templates). Let's get started.

We'll begin by installing Alcatraz. We can find an install command ready for us to copy and paste to our terminal on alcatraz.io.

We'll quit Xcode, then run this to install Acatraz into Xcode:

curl -fsSL https://raw.githubusercontent.com/supermarin/Alcatraz/deploy/Scripts/install.sh | sh

Then, we'll re-launch Xcode. We'll now see a new menu: Window > Package Manager (or ⌘⇧9).

Now, we can simple browse through the available plugins, and click to install we'd like. After installing anything, we'll need to restart Xcode to see its effect. Let's test it out now!

One incredibly simple feature missing from Xcode is the ability to quickly change the font size with ⌘+ and ⌘-.

We'll scroll down to the AdjustFontSize plugin and click Install.

We'll restart Xcode then open a project and try it out. Success! Try installing a theme or some templates next!

More info about Alcatraz can be found at alcatraz.io

Page 22 of 38