Active Filters: Swift

The Swift language is always evolving. Bugs are being fixed, new proposals are implemented, etc. It'd be great if we could try out these features out as they're being implemented, without having to wait for official releases.

Today we'll take a look at how to download, install, and try out the latest Swift Toolchain in Xcode. Let's get started!

We'll begin by heading to https://swift.org/download/ and looking for the "Snapshots" section. Here we can also find many other preview releases, etc.

Click "Xcode" to download an installer:

We'll run open the installer, and complete its steps.

We can now open Xcode and select our new Toolchain.

We can also manage Toolchains in Xcode's preferences:

With our new Toolchain selected, all builds will use it, neat!

Getting involved with Swift's development is a great way to stay informed on where things are headed. We'll look at getting even more involved in future Bites!

We've covered GCD a few times back in Bites #85 & #35. This year, GCD is getting a huge overhaul that brings it into the modern world of Swift. Today we'll take a look at what's changed, let's dive in.

TLDR: Grand Central Dispatch now has a richly typed Swift 3 API.

Here's a basic usage example:

let queue = DispatchQueue(label: "com.jakemarsh.image-processing")

queue.async {
  let thumbnail = image.resize(to: thumbnailSize(for: image))

  DispatchQueue.main.async { imageView.image = thumbnail }
}

Here we create a new queue, and enqueue some image processing work on it. Then, we do the same thing, but back on the main queue, enqueueing the work of setting resized image on our imageView there.

That's just the beginning. Here's a few more examples of how to use the new "swifty" GCD:

Time & Delay:

let delayTime = DispatchTime.now() + .seconds(1)

DispatchQueue.main.after(when: delayTime) {
  print("test")
}

For seasoned GCD users, it may take some getting used to, but the new API is much safer and more intuitive to use in Swift. Neat!

Topics

#243: The Great Swift 3 Rename 🐀

Topics

We've been able to watch Swift 3 materialize through the Swift Evolution mailing list throughout the year, and with WWDC 2016 behind us, we have a pretty clear picture of what Swift 3 will be.

Today we'll start taking a look at what's new and changed in this release, and how it can help us build our apps. First up is the "Great Rename", Let's begin.

It all started with this proposal on Swift Evolution:
"Better Translation of Objective-C APIs into Swift".

When Swift was first announced, one of the huge selling points was how we could use the same Cocoa APIs we were already familiar with.

Unfortunately, this meant a lot of Objective-C baggage found its way into the Swift code we were writing.

Swift 3 aims to fix this by improving the way Swift imports Objective-C code.

Take this Swift 2 code:

path.addLineToPoint(somePoint)

The function is imported with a definition like this:

func addLineToPoint(_: CGPoint)

In Swift 3, this would instead be imported as:

func addLine(to point: CGPoint)

And we could use it like this:

path.addLine(to: containerTop)

Swift 3 removes the repetitive names of the types, and properly brings in a (now required) argument label for the first parameter.

Additionally, Swift 3 drops the NS prefix from Foundation types, so instead of:

var now = NSDate()

We'll now be writing:

var now = Date()

Many Foundation types also now get proper Swift let/var mutability semantics:

var now = Date()
now.addTimeInterval(60) // works

let now = Date()
now.addTimeInterval(60) // compiler error

Swift 3 also prepends the word β€˜is' to imported Objective-C Boolean properties, and converts enums to be lowercased:

path.isEmpty // was just path.empty in Swift 2
var formatter = NumberFormatter()
formatter.numberStyle = .spellOut

That's all for now, next time we'll continue looking at more Swift 3 changes and enhancements.

Swift Protocols are awesome. Understanding how they can (or should) fit into our code can be tricky. Today we'll take a baby step into the world of protocols with a simple, but "real" example and try to illustrate the upsides. Let's get started.

We're going to be fancy and abstract away some of our layout code. So we'll create a little struct to hold some layout settings like this:

struct LayoutSettings {
  let direction: FlexDirection
  let justification: Justification
  let alignmentSelf: Alignment
  let alignmentChildren: Alignment

  /// ...etc
}

See? Fancy. This is great if we want to specify each individual combination each time, but it'd be nice if we could define some sort of "pre-canned" layouts that we could use by name. Sounds like a great job for a Swift Enum.

enum CannedLayout {
  case FillParent
  case SizeToFit
  case Absolute(point: CGPoint)
  case Relative(closure: (parentFrame: CGRect) -> CGSize)
}

Lovely, this will be handy. How are we going to wire all this together though? Simple, we'll make a Protocol that's only responsibility is to convert itself to a LayoutSettings.

protocol LayoutSettingsConvertible {
  func layoutSettings() -> LayoutSettings
}

LayoutSettings can adopt this extremely simply:

extension LayoutSettings : LayoutSettingsConvertible {
  func layoutSettings() -> LayoutSettings { return self }
}

Whew! That was tough.

Making our CannedLayout Enum adopt our new Protocol is a bit more involved, but really just means switch-ing over self and return the proper combination of settings for each case.

extension CannedLayout : LayoutSettingsConvertible {
  func layoutSettings() -> LayoutSettings {
    switch self {
      case .FillParent: return LayoutSettings(direction: .Vertical, justification: .Start, alignmentSelf: .Stretch, alignmentChildren: .Start)
      /// ...etc
    }
  }
}

All that's left is to use this new protocol somewhere. Let's wire this up to UIView to make it useful:

extension UIView {
  func layout(settings: LayoutSettingsConvertible) {
    /// configure the view for the new settings here
  }
}

Neat! Now, we can use configure views with one of our canned layouts:

let v = UIView(frame: .zero)
v.layout(CannedLayout.FillParent)

But we can also easily configure them the "long way" using a full LayoutSettings object directly:

let v = UIView(frame: .zero)
v.layout(LayoutSettings(direction: .Vertical, justification: .Start, alignmentSelf: .Stretch, alignmentChildren: .Start))

Now that we have this simple protocol, we can make other helper types like this:

struct Row : LayoutSettingsConvertible {
  func layoutSettings() -> LayoutSettings {
    return LayoutSettings(direction: .Horizontal, justification: .Start, alignmentSelf: .Stretch, alignmentChildren: .Start)
  }
}

That's just the basics when it comes to Protocols. They have much more to offer. More on this topic soon!

Swift Enums are super handy. With associated values, they can be used in some quite interesting ways. Today we'll check out a couple. These aren't working examples, but might spark some ideas. Let's take a look.

Enums with Extensions

Keeping colors in one place is a great way to ensure consistency in a project.

public enum Color : String {
  case Green = "28A860"
  case Blue = "3B87D6"
}

extension Color : UIColorConvertible {
  public func asColor() -> UIColor {
    return UIColor(hexString: rawValue)
  }
}

This same technique is great for images too!

Enums with Closures

This one is a little crazy (but fun!). Imagine we had our own custom system for laying out views in our app. We could not only describe that system perfectly with enums, we could even add a little more dynamic spice to the mix by making one of the associated values of our enum a closure. Neat!

public enum LayoutStrategy {
  case SizeToFit
  case Fixed(width: CGFloat, height: CGFloat)
  case Relative(closure: ((parentSize: CGSize) -> CGSize))
}

Enums can describe so many types of state and data. Know of a cool use of them? Send it to hello@littlebitesofcocoa.com and it might be featured here!

When Swift debuted, we said goodbye to using #pragma pre-processor definitions to organize our code. Don't worry, Xcode still has our backs. We can use a few different "special" comments in our code and Xcode will pick up on them and display them in its jump bar:

The extra dash character in the name of our MARK gets us those sweet separators in the source navigator dropdown.

Xcode also supports a similar bit of functionality for TODO and FIXME comments. They'll show up in bold in the same dropdown.

func launch() {
  // TODO: launch here
}

func land() {
  // FIXME: shouldn't crash
}

As a bonus, we can use a little regex magic to get Xcode to generate build warnings for TODO and FIXMEs. We'll just add a new Run Script build phase to our project that contains:

KEYWORDS="TODO|FIXME|\?\?\?:|\!\!\!:"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | \
xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | \
perl -p -e "s/($KEYWORDS)/ warning: \$1/"

Shout out to Jeffrey Sambells for originally sparking this idea!

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!

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 !

Most Swift developers are familiar with how great Swift is at integrating with Objective-C, but what about C itself? Today we'll look at how we can interact with C variables and pointers in Swift. Let's dive in.

Here's a few variables in C:

const int *someInt
int *anotherInt
struct Spaceship *spaceship

When referenced in Swift, these become:

UnsafePointer<Int>
UnsafeMutablePointer<Int>
COpaquePointer

What about those pesky void pointers in C?

void launchSpaceshipWithID(const void *spaceshipID);

Buckle up, for this we'll need to go unsafe...

Swift tries its best to keep us safe, so for something like void pointers, we'll need to jump through a few safety-defying hoops:

var sID = 31
withUnsafePointer(&sID) { (p: UnsafePointer<Int>) in
  let voidP = unsafeBitCast(p, UnsafePointer<Void>.self)
  launchSpaceshipWithID(voidP)
}

First we create a regular Int value in Swift. Nothing special. Then, we'll pass it in to the withUnsafePointer function, along with a closure. Inside, we'll be passed in an UnsafePointer version of our original Int. We'll use the unsafeBitCast function to convert it into to a void pointer. Finally, we'll pass it in the C function. Whew!

Page 2 of 4