Topics

#180: More Swift Tricks 🎩

Topics

Today we'll continue our look at interesting Swift features. Let's begin.

Type Matching with ‘is’

Try as we might, sometimes still we end up with an AnyObject or Any reference in our Swift code. We can ask if it is a given type or subtype using Swift's powerful pattern matching:

protocol Vehicle { }
struct Spaceship : Vehicle { }

let thing: Any = Spaceship()

if thing is Vehicle { print("let's move") }
else { print("can't move") }

Parsimonious Declarations

Hat tip to Erica Sadun for passing along this one. We can use a sort of Tuple-ish syntax to create a bunch of related references inline:

var (top, left, width, height) = (0.0, 0.0, 100.0, 50.0)
spaceship.width = width

Inline Closures

This technique has a few different applications, but one good example is capturing a value from a switch statement inline:

enum Theme {
  case Day, Night, Dusk, Dawn

  func apply() {
    // ...

    let backgroundColor: UIColor = {
      switch self {
        case Day: return UIColor.whiteColor()
        case Night: return UIColor.darkGrayColor()
      }
    }()

    // ... set backgroundColor on all UI elements
  }
}

Topics

#179: Swift Tricks: Properties 🎩

Topics

Today we'll look at a couple more tips for working in Swift. This time, we'll focus on Swift properties. Let's dive in.

Property Observers

In Objective-C, we'd likely use Key-Value Observing to "know" when the value of a property on one of our objects changes.

KVO still works great in Swift. In many cases, we might be able to get away with Swift's (much cleaner) property observers:

struct Spaceship {
  let name: String

  var currentSpeed: Int = 0 {
    willSet { print("About to change speed to \(newValue)") }
    didSet {
      if currentSpeed > oldValue {
        print("Increased speed to \(currentSpeed)")
      } else if currentSpeed < oldValue {
        print("Decreased speed to \(currentSpeed)")
      }
    }
  }
}

Lazy Properties

"Lazy" initialization is a great way to put off expensive work until some later time in our code. Back in Objective-C, if we wanted to "lazily" initialize a property, we might go override it's getter, and check if a private instance variable is nil or not, then populate it if it's not, then return it. Whew!

In Swift, we can forget all of this and accomplish the exact same with a simple new keyword:

lazy var couchPotatoes = [String]()

We can also use this technique to lazily init our UI elements, neat!

lazy var someLabel: UILabel = {
  let label = UILabel()
  label.translatesAutoresizingMaskIntoConstraints = false
  label.font = UIFont(name: "AvenirNext", size: 20)
  return label
}()

Localization can go a long way towards increasing the sales of our apps. Users are browsing the App Store all over the world, and when they come across a neat looking app that's not translated into their language, they're very likely to keep on scrolling. Today we’ll check out a library called Localize-Swift from Roy Marmelstein that makes this process much nicer.

The first helpful addition Localize-Swift brings us is a better way to localize our strings:

searchBar.placeholder = "Hello World".localized()

Then we can easily test our translations at runtime using:

Localize.availableLanguages()
Localize.setCurrentLanguage("fr")

We can respond to language changes using an NSNotification:

NSNotificationCenter.defaultCenter().addObserver(
  self, 
  selector: "setText",
  name: LCLLanguageChangeNotification, 
  object: nil
)

Localize-Swift also provides a custom genstrings.py script to easily fill our .strings files even though we're not using NSLocalizedString directly, neat!

More info about Localize-Swift can be found at git.io/localizeswift

Push Notifications were a fantastic addition to iOS in iOS 3. They can also sometimes be tricky to test and debug. We can save ourselves a ton of time and hassle with OS X app called Knuff. Today we'll check it out and see what it can do. Let's get started.

Before we begin, we'll install the free Knuff iOS app to make our lives a little easier in a few minutes.

We'll launch it on our iOS device (on the same Wifi network as our Mac). Knuff will display a new Devices button for us to choose our device, then it will in our push token for us.

We can use the Knuff iOS tab to try a push right away, neat!

Next, we'll switch to the Custom tab where we'll pick our app's certificate identity:

Knuff helps us by finding all the identities in our Keychain and letting us pick. (We can create a new push certificate/identity for our app with one command using fastlane's pem tool).

That's it! We can now use Knuff to configure our payload, and send pushes. Knuff even lets us save our configurations into files that we can open later for testing different notifications and scenarios.

More info about Knuff can be found at git.io/knuff

When a user first installs one of our apps, it'd be nice if we could hold their hand a bit, pointing out where the important bits are.

Today we'll look at Gecco, a library that can make creating these walkthroughs quite easy. Let's dive in.

Gecco is built using UIKit's custom transition protocols.

This means there's simply a view controller that we'll configure and present over our content that will display the "spotlight" effect.

In it's most basic form, we can use Gecco by creating a SpotlightViewController, then configuring it's spotlight property to be one of the supplied Oval, Rect, or RoundRect enum cases:

let spotlightVC = SpotlightViewController()

spotlightVC.spotlight = .Oval(
  center: CGPointMake(100, 100),
  width: 100)

presentViewController(spotlightVC, animated: true, completion: nil)

Then we simply present it like normal, neat! In simple cases this is all we need, next we'll look at customizing things further.

We can actually subclass Gecco's SpotlightViewController and use it's spotlightView property to animate the spotlight effect calling out different shapes, even morphing from one to another:

class CustomSpotlightViewController : SpotlightViewController {
  var currentStep = 0
  func updateSpotlightView() {
    switch currentStep {
      case 0: spotlight = .Oval(center: CGPointMake(349, 42), width: 50)
      case 1: spotlightView.move(.Oval(center: CGPointMake(300, 42), width: 50))
      case 2: spotlightView.move(.RoundedRect(center: CGPointMake(375 / 2, 42), size: CGSizeMake(120, 40), radius: 6), moveType: .Disappear)
      case 3: dismissViewControllerAnimated(true, completion: nil)
      default: break
    }

    currentStep++
  }
}

Note about hard-coding values: We've used exact values here to make it easy to understand how Gecco works. In a real world scenario, you would probably be grabbing these values from your views after they've been through a layout pass.

More info about Gecco can be found at git.io/gecco

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!

Topics

#175: More Swift Tricks 🎩

Topics

Today we'll continue our look at interesting Swift features. Let's begin.

Multiple/Chained Optional Unwrapping

This is great when we've got multiple optionals to unwrap. We can even use unwrapped references from earlier in the statement in later parts of the statement. Neat!

if let URL = NSURL(string: someURL),
   let data = NSData(contentsOfURL: URL),
   let ship = Spaceship(data: data) {
    // use 'ship'
}

Multiple Initialization

We can initialize multiple references in one statement (and one line). This works for when using both let and var:

let ship1 = "Tantive IV", ship2 = "Ghost", ship3 = "Outrider"

Slicker Array Inits

We can simplify Array (and Dictionary) init statements like this:

let spaceships: [Spaceship] = []

To this:

let spaceships = [Spaceship]()

Semicolons: Gone but not forgotten!

Removing the need for trailing semicolons was one of Swift's most welcome features. However, they actually are present in Swift, and can serve a useful purpose. They'll let us write multiple statements on one line. This works great (for example) in guard statements:

guard let error == nil else { fail(error!); return }

iOS has some great built-in support for different keyboards for different types of data, but the built-in numeric-keypad keyboard style does leave a few things to be desired (a "done" button, decimal point, a "hide" button, etc).

Today we'll look at a library called MMNumberKeyboard by Matías Martínez that does a great job of filling in these gaps. Let's try it out.

Setting up a text field to use the library's keyboard is extremely straightforward. First we'll create and configure the keyboard:

let numberKeyboard = MMNumberKeyboard(frame: CGRectZero)
numberKeyboard.allowsDecimalPoint = true
numberKeyboard.delegate = self

Then we'll set it as the inputView of our text field:

spaceshipPriceTextField = UITextField(frame: CGRectZero)
spaceshipPriceTextField.inputView = numberKeyboard

Now, when our text field becomes the first responder, the keyboard will be much more useful. Lastly, we can (optionally) add some delegate functions:

func numberKeyboard(numberKeyboard: MMNumberKeyboard!, shouldInsertText text: String!) -> Bool
func numberKeyboardShouldReturn(numberKeyboard: MMNumberKeyboard!) -> Bool

More info about MMNumberKeyboard can be found at git.io/numberkeyboard

Optionals in Swift are a great way for us to represent either some value, or no value at all. Like many parts of Swift, they're actually built (mostly) in Swift itself. Today we'll pop the hood, and take a look at how they work. Let's get started.

We'll begin by heading over to the definition of the Optional enum in the Swift headers. We can get here by pressing ⌘⇧O, then typing "Optional":

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
  case None
  case Some(Wrapped)
  // ...

Right away we'll see that Optional types are merely an enum with an associated value. That associated value has a type, but it's a generic placeholder for whatever type we'll make Optional references to. The trailing-? syntax is merely syntactic sugar, for example:

String?

is simply a shorthand way of writing:

Optional<String>

Swift enums really show their power here, we're able to represent a fairly high level concept, with this relatively simple construct. Next, let's look at initializing Optionals.

/// ...

public init()

public init(_ some: Wrapped)

The first init statement handles Optionals with no value, the second handles the presence of some value. Additionally, Optional adopts NilLiteralConvertable, so all three of these statements mean the same thing:

let foo: String? = nil
let foo = Optional<String>()
let foo: String? = .None

Similarly, these are also the same:

let foo: String? = "Hello"
let foo = Optional<String>("Hello")
let foo: String? = .Some("Hello")

Topics

#172: UIMenuController Basics 💬

Topics

Menus have been a part of iOS since iOS 3. They're those little black bubbles that often contain copy/paste/etc options.

They're great for offering more intermediate or advanced features right in-context over the content they'll manipulate.

Today we'll take a look at the basics of getting them working in our own view controllers. Let's get started:

First we'll add a function for when our menu item is selected:

class SpaceshipsViewController : UIViewController {
  func copySpaceship() {
    // do the thing
  }
}

Then we'll need to override a couple of functions:

extension SpaceshipsViewController {
  override func canBecomeFirstResponder() -> Bool {
    return true
  }

  override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
    switch action {
    case Selector("copySpaceship"): return true
    default: return false
    }
  }
}

Next, we'll need to actually show our menu. There are plenty of ways to do this, but one common technique is a long press gesture recognizer:

view.addGestureRecognizer(
  UILongPressGestureRecognizer(
    target: self, 
    action: Selector("showMenu")
  )
)

Finally, we'll implement our showMenu function:

func showMenu() {
  becomeFirstResponder()

  let menu = UIMenuController.sharedMenuController()
  menu.menuItems = [UIMenuItem(title: "Copy", action: Selector("copySpaceship"))]

  menu.setTargetRect(view.bounds, inView: view)
  menu.setMenuVisible(true, animated: true)
}

Success!

Page 19 of 38