Topics

#205: Swift guard Basics ⚔

Topics

The guard statement was added to Swift in its 2.0 release. It can dramatically increase the readability and clarity of the conditional checks in our code.

It supports Swift's inline optional unwrapping as well as pattern matching. Let's try it out!

We can think of the guard statement like a sort of inverted if statement. We essentially say: "this thing must be true otherwise we're bailing out!". Here's a fairly full-featured example:

func launch() {
  guard let fc = fuelCell where fc.level > 0.5 else {
    showLowFuelWarning()
    return
  }

  startEngines()
  // ...etc
}

Here we're ensuring that we have a fuelCell using optional unwrapping, then using pattern matching to make sure that our (now unwrapped optional) fuel cell has enough fuel in it for us to launch. Right away we can start to see how much clarity this adds.

If either part of our condition fails, we use the else block to run some code then return from the function.

Also as a bonus, the variables we unwrapped in the guard statement are now available, unwrapped, and in-scope for the rest of our function (anything below the guard statement). Neat!

This allows the rest of our function to focus on the actual work being done, rather than checking for validity throughout. We can stack these up too, it's quite common to see multiple guard statements at the top of a functions in Swift.

It's important to note that we aren't required to return at the end of a guard's else block. Imagine using guard in loops to continue, or in a function that throws to throw an error. Guard helps keep our code clean and readable. Happy guarding!

Today we'll continue looking at initialization in Swift with Designated Initializers. Let's get started.

Swift's initialization system is made up of what are essentially a set of rules. We'll step through them here. Let's start with a class.

The first rule of Designated Initializers is that we need one. All classes must define (or inherit) at least one.

Ok, we've added one designated and one convenience initializer. Not too shabby. Now, let's use this base class.

Uh oh, what's going on here? Turns out it's the next rule. We're writing the designated initializer for Peakachew. Designated initializers must call a designated initializer from their immediate superclass, not a convenience one like we tried to do here.

Well, we've fixed our first problem but we've hit the next rule. Designated initializers have to initialize all stored properties on their class before calling super.

Lastly, designated initializers must call their parent class's initializer before assigning a value to any properties they've inherited from it.

With that, we're done. We're now following all the rules:

class Monster {
  var name: String

  init(name: String) {
    self.name = name
  }

  convenience init() {
    self.init(name: "Nameless Monster")
  }
}

class Peakachew : Monster {
  var shouldFollow: Bool

  init(shouldFollow: Bool) {
    self.shouldFollow = shouldFollow

    super.init(name: "Peakachew")
  }
}

Whew!

More on initializing in Swift next time!

Often when working with data from an API or third-party we'll need to manipulate or analyze it in a very specific way. In these cases, many of us simply search Google for "how to do the thing to a String in Swift". This usually works out fine, but what a bummer.

Today we'll check out a library from Andrew Mayne called SwiftString, which can help us here.

SwiftString is essentially a collection of a ton of String manipulation and analysis utilities. It has functions like this:

"<rock>blah</hardplace>".between("<rock>", "</hardplace>") // "blah"
"hello".isNumeric() // false
"hello7".isNumeric() // false
"31.0".isNumeric() // true
"-31.0".isNumeric() // true
"star wars".split(" ")[0] // "star"
"star wars"[0...1] // "st"
"#203: Simplifying Common String Operations".slugify() // "203-simplifying-common-string-operations"
"Some [string], *with* %junk in it.)".stripPunctuation() // "Some string with junk in it"
"yay &quot;strings&quot;".decodeHTML() // "yay \"strings\""

We might only need one or two of these functions in a single app, but thanks to SwiftString, we'll never have to write them ourselves again.

More info about SwiftString can be found at git.io/swiftstring

Following up on Bite #201 about reporting bugs to Apple, today we'll take a look at a tool that makes reporting bugs even easier called QuickRadar. It's great and will give us a chance to discuss one more piece of this puzzle, OpenRadar.

QuickRadar is a open-source menu bar app for OS X that simplifies and improves upon the "traditional" bug reporting process we looked at in Bite #201. We can download it for free from quickradar.com. We'll move it over to /Applications, then start it up.

We can head over to QuickRadar's preferences to fill in our Apple ID credentials.

Next, we'll select New Radar... to see the app's main interface. Here we can describe our bug, drag in a sample project, etc.

We'll see another option at the bottom: "Send to Open Radar". Open Radar is a site run by the community that catalogs and allows us to search/compare bugs with each other.

Usually we have to post them there manually, but with QuickRadar, we'll just add our credentials in preferences, then check the box. Finally, to ease confusion, links like rdar://12345 only work for Apple employees.

QuickRadar is available at quickradar.com

Open Radar is at openradar.me

Topics

#201: How to File a Bug with Apple 🐞

Topics

We've all been there. We hit a bug, and after a bit of debugging we determine the cause actually lives in one of Apple's frameworks. 😱Perhaps even worse, we find a crashing bug in Xcode itself 😨. When we hit these types of issues, our first step to getting it fixed should be reporting the bug to Apple. Today we'll check out how to do it. Let's begin.

We'll start by going to bugreport.apple.com and logging in with our developer account Apple ID.

Once inside, we'll see a delightful iOS 6-ish interface. Yeah... Anyways, we'll click the New button to get started.

Next, we'll select the platform/product we're reporting for.

Finally, we'll be shown the main New Problem form. Most of the fields are self explanatory, but don't feel too boxed in by the format. Just be direct, describe the exact problem as we'd want to hear it described ourselves (imagine if we were the ones tasked to fix it!)

Here's a quick example:

Apple's internal “Radar” system for tracking these reports has gotten a bad rep. In truth though, it's our only way to get these types of issues in front of the eyes of the engineers who need to know about them. Now go forth, and report all the things!

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!

Way back in Bite #1 (zomg!) we talked about initializing View Controllers in Swift. Swift's init functions are still a source of confusion for many newcomers. Today we'll look at a couple cases where Swift synthesizes inits for us.

Structs

Swift offers free "memberwise" initializers for Structs. This means that if we define a Struct, and opt not to define any initializers, one will be synthesized for us, under the hood, using the properties we've given to the Struct. If we add our own though, we lose the synthesized init, and become responsible for defining 100% for the Struct's inits.

struct Spaceship {
  var name: String
}

let ship = Spaceship(name: "Outrider")

Default Initializers

Classes can synthesize a default init function for us. Only one that accepts 0 parameters, though. We'll get this if we define a class, while assigning default values to all its properties:

class Spaceship {
  var topSpeed = 1000
  var currentSpeed = 0
}
let ship = Spaceship()

There's plenty to cover about init'ing things in Swift. We'll take a look in future Bites. Oh, and happy 200th Bite !

iOS gives us a ton of great capabilities to build upon. Being able to use the user's current geographic location in our apps really has changed the world.

We always need to ask for the user's permission first though, so we might as well do it in style! Today we'll check out a simple yet beautiful library from Sven Tiigi called STLocationRequest that uses Flyover to provide a great looking "location access prompt" view controller.

We'll begin by importing STLocationRequest, and configuring and showing a location request controller.

self.showLocationRequestController(
  setTitle: "Allow location access?", 
  setAllowButtonTitle: "Sure", 
  setNotNowButtonTitle: "Nope", 
  setMapViewAlphaValue: 0.7, 
  setBackgroundViewColor: .orangeColor()
)

Then, we can subscribe to the NSNotifications the library posts to know how the user responds.

More info about STLocationRequest can be found at git.io/stlocationrequest

Vector graphics are fantastic. They give us small, compressible files, crispy rendered pixels at any scale, and they're supported by many different kinds of software and frameworks.

Except iOS 😭, which doesn't support them out of the box. Today we'll try a library from Michael Choe called SwiftSVG which provides great support for parsing and rendering SVG files. Let's take a look.

SwiftSVG supports a ton of different ways of getting SVGs into our app.

CAShapeLayer(SVGURL: SVGURL)
UIView(SVGURL: SVGURL)
UIView(pathString: deathStarBlueprints)
CAShapeLayer(pathString: superSecretNewLogoIdea)
UIBezierPath(pathString: "M150 0 L75 200 L225 200 Z")

SwiftSVG also provides a custom UIView subclass we can use in Interface Builder that supports IBInspectable/IBDesignable.

More broadly, it's important to think about the reasons why we might want to use SVGs in our app. SVGs are essentially XML files (Open one up in a text editor, you'll see.)

They are instructions on how to draw a set of paths. The files are incredibly small.

Getting a good workflow going for creating them at-will can be tricky, but Sketch (eventually) makes it mostly painless.

Once we have this, we can build some awesome abstractions. Imagine a Swift struct with SVGName, color, and size that can produces a UIImage.

struct SVGImage {
  let SVGName: String
  let size: CGSize
  let color: UIColor

  func asImage() -> UIImage {
    // Neato!
  }
}

More info about SwiftSVG can be found at git.io/swiftsvg

It happens to the best of us. We're going along, composing some UIViews in our app. We're styling them, configuring them, we can't wait to try them out. That's when we see it. A big, empty, unescapable void of nothingness right where our views should be! 😱

Today we'll look at some tips to solve a case of missing UIViews.

First, we should arm ourselves with tools to help inspect what's going on. Xcode's own View Debugger is a great place to start, and Reveal.app is a fantastic third-party solution.

Whether it's one of these tools, or simply writing some in-depth logging functions, our first step should be to look at both our view hierarchy and its layout for anything funky.

print(UIApplication.sharedApplication().keyWindow?
  .performSelector("recursiveDescription"))

We can use private functions like recursiveDescription to print out a handy tree-view of our views to Xcode's Console.

Most of these debugging sessions stop here, as the problem often involves a view not being in the correct place in the hierarchy, or Auto Layout has gone and done something wacky with our views' locations.

If we're still stuck though, here are some sanity checks we can perform:

  • Are any views hidden?
  • How about transparent? (0 alpha)
  • Is it masked via a maskLayer?
  • Does it have a CGRectZero frame?
  • Is the key UIWindow a weird size or in a weird place?

Try making each view a specific ugly color (the static .XColor() functions on UIColor work wonders here).

  • Is another view covering it up?
  • Is .clipsToBounds enabled and a strange frame/bounds is causing the view to be clipped?

If all else fails, comment out everything, and add it back one bit at a time until something fails.

Happy 🐞 hunting!

Page 16 of 38