Create A Stack View With Custom Spacing iOS 11 Swift 4 XCode 9

When Apple introduced stack views in iOS 9 they made it much easier to use Auto Layout by reducing the number of constraints you needed to create yourself for many common layouts. One edge case that was not well covered was the need for custom spacing between views. You could do it by nesting stack views but that always seemed an unnecessary complication. In iOS 11 you can create stack views with custom spacing between views.

The Problem

Here is the example layout I want to create:

I have a total of five labels. A header label with a larger font size, three labels and small font size footer. The three middle labels have spacing of 8 points but I want the header and footer to have 32 points of spacing.

This vertical arrangement of views is perfect for a UIStackView apart from the spacing. The spacing property of a stack view applies equally to the arranged subviews.

Stacking Stacks

One way to create the layout without needing spacer views is to embed an inner stack view.

The inner stack view with the three labels has 8 point spacing and the outer stack view has 32 points of spacing. This works but can quickly get messy. For example, if I wanted different spacing for the header and footer.

Custom Spacing (iOS 11)

New in iOS 11 it is possible to customize the spacing after any of the arranged subviews of a stack view. Assuming we have our labels already created the code to setup the stack view might be something like this:

let stackView = UIStackView(arrangedSubviews: [headerLabel, topLabel, middleLabel, bottomLabel, footerLabel])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 8.0

This gives us 8 points of spacing between the arranged subviews. To get the extra spacing after the header label and before the footer label:

// iOS 11 only
stackView.setCustomSpacing(32.0, after: headerLabel)
stackView.setCustomSpacing(32.0, after: bottomLabel)

Notes:

  • You always specify the spacing after the arranged subview. There is no method to specify spacing before a view.
  • There is no way to specify this custom spacing in Interface Builder. You need to do it in code.
  • When you remove the subview from the stack view the system removes the custom spacing.

Standard and Default Spacing

There are two new type properties on the UIStackView class in iOS 11 that define default and system spacing:

class let spacingUseDefault: CGFloat
class let spacingUseSystem: CGFloat

You cannot rely on the values that these properties return. The actual values are tokens used to ask for the default or system spacing. System spacing seems to give 8 points of spacing on an iPhone but again you should not rely on the actual value.

You can use these to set or reset the custom spacing after a view. For example to use the system defined spacing after the top label:

stackview.setCustomSpacing(UIStackView.spacingUseSystem, after: topLabel)

To reset the spacing after this label back to the value of the spacing property (removing the custom spacing):

stackview.setCustomSpacing(UIStackView.spacingUseDefault, after: topLabel)
Advertisements
Create A Stack View With Custom Spacing iOS 11 Swift 4 XCode 9

What’s New in Swift 4

API Changes

Before jumping right into additions introduced in Swift 4, let’s first take a look at what changes/improvements it makes to existing APIs.

Strings

String is receiving a lot of well deserved love in Swift 4. This proposal contains many changes, so let’s break down the biggest. [SE-0163]:

In case you were feeling nostalgic, strings are once again collections like they were pre Swift 2.0. This change removes the need for a characters array on String. You can now iterate directly over a String object:

let galaxy = "Milky Way 🐮"
for char in galaxy {
  print(char)
}

Not only do you get logical iteration through String, you also get all the bells and whistles from Sequence and Collection:

galaxy.count       // 11
galaxy.isEmpty     // false
galaxy.dropFirst() // "ilky Way 🐮"
String(galaxy.reversed()) // "🐮 yaW ykliM"

// Filter out any none ASCII characters
galaxy.filter { char in
  let isASCII = char.unicodeScalars.reduce(true, { $0 && $1.isASCII })
  return isASCII
} // "Milky Way "

The ASCII example above demonstrates a small improvement to Character. You can now access the UnicodeScalarView directly from Character. Previously, you needed to instantiate a new String [SE-0178].

Another addition is StringProtocol. It declares most of the functionality previously declared on String. The reason for this change is to improve how slices work. Swift 4 adds the Substring type for referencing a subsequence on String.

Both String and Substring implement StringProtocol giving them almost identical functionality:

// Grab a subsequence of String
let endIndex = galaxy.index(galaxy.startIndex, offsetBy: 3)
var milkSubstring = galaxy[galaxy.startIndex...endIndex]   // "Milk"
type(of: milkSubstring)   // Substring.Type

// Concatenate a String onto a Substring
milkSubstring += "🥛"     // "Milk🥛"

// Create a String from a Substring
let milkString = String(milkSubstring) // "Milk🥛"

Another great improvement is how String interprets grapheme clusters. This resolution comes from the adaptation of Unicode 9. Previously, unicode characters made up of multiple code points resulted in a count greater than 1. A common situation where this happens is an emoji with a selected skin-tone. Here are a few examples showing the before and after behavior:

"👩‍💻".count // Now: 1, Before: 2
"👍🏽".count // Now: 1, Before: 2
"👨‍❤️‍💋‍👨".count // Now: 1, Before, 4

This is only a subset of the changes mentioned in the String Manifesto. You can read all about the original motivations and proposed solutions you’d expect to see in the future.

Dictionary and Set

As far as Collection types go, Set and Dictionary aren’t always the most intuitive. Lucky for us, the Swift team gave them some much needed love with [SE-0165].

Sequence Based Initialization
First on the list is the ability to create a dictionary from a sequence of key-value pairs (tuple):

let nearestStarNames = ["Proxima Centauri", "Alpha Centauri A", "Alpha Centauri B", "Barnard's Star", "Wolf 359"]
let nearestStarDistances = [4.24, 4.37, 4.37, 5.96, 7.78]

// Dictionary from sequence of keys-values
let starDistanceDict = Dictionary(uniqueKeysWithValues: zip(nearestStarNames, nearestStarDistances)) 
// ["Wolf 359": 7.78, "Alpha Centauri B": 4.37, "Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Barnard's Star": 5.96]

Duplicate Key Resolution
You can now handle initializing a dictionary with duplicate keys any way you’d like. This helps avoid overwriting key-value pairs without any say in the matter:

// Random vote of people's favorite stars
let favoriteStarVotes = ["Alpha Centauri A", "Wolf 359", "Alpha Centauri A", "Barnard's Star"]

// Merging keys with closure for conflicts
let mergedKeysAndValues = Dictionary(zip(favoriteStarVotes, repeatElement(1, count: favoriteStarVotes.count)), uniquingKeysWith: +) // ["Barnard's Star": 1, "Alpha Centauri A": 2, "Wolf 359": 1]

The code above uses zip along with the shorthand + to resolve duplicate keys by adding the two conflicting values.

Note: If you are not familiar with zip, you can quickly learn about it in Apple’s Swift Documentation

Filtering
Both Dictionary and Set now have the ability to filter results into a new object of the original type:

// Filtering results into dictionary rather than array of tuples
let closeStars = starDistanceDict.filter { $0.value < 5.0 }
closeStars // Dictionary: ["Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Alpha Centauri B": 4.37]

Dictionary Mapping
Dictionary gained a very useful method for directly mapping its values:

// Mapping values directly resulting in a dictionary
let mappedCloseStars = closeStars.mapValues { "\($0)" }
mappedCloseStars // ["Proxima Centauri": "4.24", "Alpha Centauri A": "4.37", "Alpha Centauri B": "4.37"]

Dictionary Default Values
A common practice when accessing a value on Dictionary is to use the nil coalescing operator to give a default value in case the value is nil. In Swift 4, this becomes much cleaner and allows you to do some awesome in line mutation:

// Subscript with a default value
let siriusDistance = mappedCloseStars["Wolf 359", default: "unknown"] // "unknown"

// Subscript with a default value used for mutating
var starWordsCount: [String: Int] = [:]
for starName in nearestStarNames {
  let numWords = starName.split(separator: " ").count
  starWordsCount[starName, default: 0] += numWords // Amazing 
}
starWordsCount // ["Wolf 359": 2, "Alpha Centauri B": 3, "Proxima Centauri": 2, "Alpha Centauri A": 3, "Barnard's Star": 2]

Previously this type of mutation would need wrapping in a bloated if-let statement. In Swift 4 it’s possible all in a single line!

Dictionary Grouping
Another amazingly useful addition is the ability to initialize a Dictionary from a Sequence and to group them into buckets:

// Grouping sequences by computed key
let starsByFirstLetter = Dictionary(grouping: nearestStarNames) { $0.first! }

// ["B": ["Barnard's Star"], "A": ["Alpha Centauri A", "Alpha Centauri B"], "W": ["Wolf 359"], "P": ["Proxima Centauri"]]

This comes in handy when grouping data by a specific pattern.

Reserving Capacity
Both Sequence and Dictionary now have the ability to explicitly reserve capacity.

// Improved Set/Dictionary capacity reservation
starWordsCount.capacity  // 6
starWordsCount.reserveCapacity(20) // reserves at _least_ 20 elements of capacity
starWordsCount.capacity // 24

Reallocation can be an expensive task on these types. Using reserveCapacity(_:) is an easy way to improve performance when you have an idea how much data it needs to store.

That was a ton of info, so definitely check out both types and look for ways to use these additions to spice up your code.

Private Access Modifier

An element of Swift 3 some haven’t been too fond of was the addition of fileprivate. In theory, it’s great, but in practice its usage can often be confusing. The goal was to use private within the member itself, and to use fileprivate rarely in situations where you wanted to share access across members within the same file.

The issue is that Swift encourages using extensions to break code into logical groups. Extensions are considered outside of the original member declaration scope, which results in the extensive need for fileprivate.

Swift 4 realizes the original intent by sharing the same access control scope between a type and any extension on said type. This only holds true within the same source file [SE-0169]:

struct SpaceCraft {
  private let warpCode: String

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

extension SpaceCraft {
  func goToWarpSpeed(warpCode: String) {
    if warpCode == self.warpCode { // Error in Swift 3 unless warpCode is fileprivate
      print("Do it Scotty!")
    }
  }
}

let enterprise = SpaceCraft(warpCode: "KirkIsCool")
//enterprise.warpCode  // error: 'warpCode' is inaccessible due to 'private' protection level
enterprise.goToWarpSpeed(warpCode: "KirkIsCool") // "Do it Scotty!"

This allows you to use fileprivate for its intended purpose rather than as a bandaid to code organization.

API Additions

Now let’s take a look at the new shinny features of Swift 4. These changes shouldn’t break your existing code as they are simply additive.

Archival and Serialization

Up to this point in Swift, to serialize and archive your custom types you’d have to jump through a number of hoops. For class types you’d need to subclass NSObject and implement the NSCoding protocol.

Value types like struct and enum required a number of hacks like creating a sub object that could extend NSObject and NSCoding.

Swift 4 solves this issue by bringing serialization to all three Swift types [SE-0166]:

struct CuriosityLog: Codable {
  enum Discovery: String, Codable {
    case rock, water, martian
  }

  var sol: Int
  var discoveries: [Discovery]
}

// Create a log entry for Mars sol 42
let logSol42 = CuriosityLog(sol: 42, discoveries: [.rock, .rock, .rock, .rock])

In this example you can see that the only thing required to make a Swift type Encodable and Decodable is to implement the Codable protocol. If all properties are Codable, the protocol implementation is automatically generated by the compiler.

To actually encode the object, you’ll need to pass it to an encoder. Swift encoders are being actively implemented in Swift 4. Each encodes your objects according to different schemes [SE-0167] (Note: Part of this proposal is still in development):

let jsonEncoder = JSONEncoder() // One currently available encoder

// Encode the data
let jsonData = try jsonEncoder.encode(logSol42)
// Create a String from the data
let jsonString = String(data: jsonData, encoding: .utf8) // "{"sol":42,"discoveries":["rock","rock","rock","rock"]}"

This took an object and automatically encoded it as a JSON object. Make sure to check out the properties JSONEncoder exposes to customize its output.

The last part of the process is to decode the data back into a concrete object:

let jsonDecoder = JSONDecoder() // Pair decoder to JSONEncoder

// Attempt to decode the data to a CuriosityLog object
let decodedLog = try jsonDecoder.decode(CuriosityLog.self, from: jsonData)
decodedLog.sol         // 42
decodedLog.discoveries // [rock, rock, rock, rock]

With Swift 4 encoding/decoding you get the type safety expected in Swift without relying on the overhead and limitations of @objc protocols.

Key-Value Coding

Up to this point you could hold reference to functions without invoking them because functions are closures in Swift. What you couldn’t do is hold reference to properties without actually accessing the underlying data held by the property.

A very exciting addition to Swift 4 is the ability to reference key paths on types to get/set the underlying value of an instance [SE-0161]:

struct Lightsaber {
  enum Color {
    case blue, green, red
  }
  let color: Color
}

class ForceUser {
  var name: String
  var lightsaber: Lightsaber
  var master: ForceUser?

  init(name: String, lightsaber: Lightsaber, master: ForceUser? = nil) {
    self.name = name
    self.lightsaber = lightsaber
    self.master = master
  }
}

let sidious = ForceUser(name: "Darth Sidious", lightsaber: Lightsaber(color: .red))
let obiwan = ForceUser(name: "Obi-Wan Kenobi", lightsaber: Lightsaber(color: .blue))
let anakin = ForceUser(name: "Anakin Skywalker", lightsaber: Lightsaber(color: .blue), master: obiwan)

Here you’re creating a few instances of force users by setting their name, lightsaber, and master. To create a key path, you simply use a back-slash followed by the property you’re interested in:

// Create reference to the ForceUser.name key path
let nameKeyPath = \ForceUser.name

// Access the value from key path on instance
let obiwanName = obiwan[keyPath: nameKeyPath]  // "Obi-Wan Kenobi"

In this instance, you’re creating a key path for the name property of ForceUser. You then use this key path by passing it to the new subscript keyPath. This subscript is now available on every type by default.

Here are more examples of ways to use key paths to drill down to sub objects, set properties, and build off key path references:

// Use keypath directly inline and to drill down to sub objects
let anakinSaberColor = anakin[keyPath: \ForceUser.lightsaber.color]  // blue

// Access a property on the object returned by key path
let masterKeyPath = \ForceUser.master
let anakinMasterName = anakin[keyPath: masterKeyPath]?.name  // "Obi-Wan Kenobi"

// Change Anakin to the dark side using key path as a setter
anakin[keyPath: masterKeyPath] = sidious
anakin.master?.name // Darth Sidious

// Note: not currently working, but works in some situations
// Append a key path to an existing path
//let masterNameKeyPath = masterKeyPath.appending(path: \ForceUser.name)
//anakin[keyPath: masterKeyPath] // "Darth Sidious"

The beauty of key paths in Swift is that they are strongly typed! No more of that Objective-C string style mess!

Multi-line String Literals

A very common feature to many programming languages is the ability to create a multi-line string literal. Swift 4 adds this simple but useful syntax by wrapping text within three quotes [SE-0168]:

let star = "⭐️"
let introString = """
  A long time ago in a galaxy far,
  far away....

  You could write multi-lined strings
  without "escaping" single quotes.

  The indentation of the closing quotes
       below deside where the text line
  begins.

  You can even dynamically add values
  from properties: \(star)
  """
print(introString) // prints the string exactly as written above with the value of star

This is extremely useful when building XML/JSON messages or when building long formatted text to display in your UI.

One-Sided Ranges

To reduce verbosity and improve readability, the standard library can now infer start and end indices using one-sided ranges [SE-0172].

One way this comes in handy is creating a range from an index to the start or end index of a collection:

// Collection Subscript
var planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
let outsideAsteroidBelt = planets[4...] // Before: planets[4..<planets.endIndex]
let firstThree = planets[..<4]          // Before: planets[planets.startIndex..<4]

As you can see, one-sided ranges reduce the need to explicitly specify either the start or end index.

Infinite Sequence
They also allow you to define an infinite Sequence when the start index is a countable type:

// Infinite range: 1...infinity
var numberedPlanets = Array(zip(1..., planets))
print(numberedPlanets) // [(1, "Mercury"), (2, "Venus"), ..., (8, "Neptune")]

planets.append("Pluto")
numberedPlanets = Array(zip(1..., planets))
print(numberedPlanets) // [(1, "Mercury"), (2, "Venus"), ..., (9, "Pluto")]

Pattern Matching
Another great use for one-sided ranges is pattern matching:

// Pattern matching

func temperature(planetNumber: Int) {
  switch planetNumber {
  case ...2: // anything less than or equal to 2
    print("Too hot")
  case 4...: // anything greater than or equal to 4
    print("Too cold")
  default:
    print("Justtttt right")
  }
}

temperature(planetNumber: 3) // Earth

Generic Subscripts

Subscripts are an important part of making data types accessible in an intuative way. To improve their usefulness, subscripts can now be generic [SE-0148]:

struct GenericDictionary<Key: Hashable, Value> {
  private var data: [Key: Value]

  init(data: [Key: Value]) {
    self.data = data
  }

  subscript<T>(key: Key) -> T? {
    return data[key] as? T
  }
}

In this example, the return type is generic. You can then use this generic subscript like so:

// Dictionary of type: [String: Any]
var earthData = GenericDictionary(data: ["name": "Earth", "population": 7500000000, "moons": 1])

// Automatically infers return type without "as? String"
let name: String? = earthData["name"]

// Automatically infers return type without "as? Int"
let population: Int? = earthData["population"]

Not only can the return type be generic, but the actual subscript type can be generic as well:

extension GenericDictionary {
  subscript<Keys: Sequence>(keys: Keys) -> [Value] where Keys.Iterator.Element == Key {
    var values: [Value] = []
    for key in keys {
      if let value = data[key] {
        values.append(value)
      }
    }
    return values
  }
}

// Array subscript value
let nameAndMoons = earthData[["moons", "name"]]        // [1, "Earth"]
// Set subscript value
let nameAndMoons2 = earthData[Set(["moons", "name"])]  // [1, "Earth"]

In this example, you can see that passing in two different Sequence type (Array and Set) results in an array of their respective values.

Miscellaneous

That handles the biggest changes in Swift 4. Now let’s go a little more rapidly through some of the smaller bits and pieces.

MutableCollection.swapAt(_:_:)

MutableCollection now has the mutating method swapAt(_:_:) which does just as it sounds; swap the values at the given indices [SE-0173]:

// Very basic bubble sort with an in-place swap
func bubbleSort<T: Comparable>(_ array: [T]) -> [T] {
  var sortedArray = array
  for i in 0..<sortedArray.count - 1 {
    for j in 1..<sortedArray.count {
      if sortedArray[j-1] > sortedArray[j] {
        sortedArray.swapAt(j-1, j) // New MutableCollection method
      }
    }
  }
  return sortedArray
}

bubbleSort([4, 3, 2, 1, 0]) // [0, 1, 2, 3, 4]

Associated Type Constraints

You can now constrain associated types using the where clause [SE-0142]:

protocol MyProtocol {
  associatedtype Element
  associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
}

Using protocol constraints, many associatedtype declarations could constrain their values directly without having to jump through hoops.

Class and Protocol Existential

A feature that has finally made it to Swift from Objective-C is the ability to define a type that conforms to a class as well as a set of protocols [SE-0156]:

protocol MyProtocol { }
class View { }
class ViewSubclass: View, MyProtocol { }

class MyClass {
  var delegate: (View & MyProtocol)?
}

let myClass = MyClass()
//myClass.delegate = View() // error: cannot assign value of type 'View' to type '(View & MyProtocol)?'
myClass.delegate = ViewSubclass()

Limiting @objc Inference

To expose or your Swift API to Objective-C, you use the @objc compiler attribute. In many cases the Swift compiler inferred this for you. The three main issues with mass inference are:

    1. Potential for a significant increase to your binary size
    2. Knowing when @objc will

be inferred isn’t obvious

  1. The increased chance of inadvertently creating an Objective-C selector collisions.

Swift 4 takes a stab at solving this by limiting the inference of @objc [SE-0160]. This means that you’ll need to use @objc explicitly in situations where you want the full dynamic dispatch capabilities of Objective-C.

A few examples of where you’ll need to make these changes include private methods, dynamic declarations, and any methods of NSObject subclasses.

NSNumber Bridging

There have been many funky behaviors between NSNumber and Swift numbers that have been haunting the language for too long. Lucky for us, Swift 4 squashes those bugs [SE-0170].

Here’s an example demonstrating an example of the behavior:

let n = NSNumber(value: 999)
let v = n as? UInt8 // Swift 4: nil, Swift 3: 231

The weird behavior in Swift 3 shows that if the number overflows, it simply starts over from 0. In this example, 999 % 2^8 = 231.

Swift 4 solves the issue by forcing optional casting to return a value only if the number can be safely expressed within the containing type.

What’s New in Swift 4

WWDC 2017 Update

Xcode 9

Personally, the thing I get most excited for each WWDC is the new version of Xcode. This year, Xcode 9 was announced, and it represents a huge update with a lot of major changes we’re all going to love.

New Editor

Xcode 9 has a brand new Source Editor, entirely written in Swift. In the new editor you can use the Fix interface to fix multiple issues at once. Also, when mousing around your projects, you can hold the Command key and visually see how structures in your code are organized:

wwdc 2017

One announcement that received a strong ovation was Xcode 9 will now increase or decrease font size in the Source Editor with Command-+ or Command– – the keyboard shortcut shared by many other text editors.

And as an added bonus, the new source editor also includes an integrated Markdown editor (which will really help create some nice looking GitHub READMEs).

Refactoring

I’ve been excitedly anticipating Xcode’s ability to refactor Swift code for as long as Swift has been a thing. IDE-supported refactoring has long been a standard for top-tier development environments, and it’s so good to see this is now available in Xcode 9 for Swift code (in addition to Objective-C, C++ and C). One of the most basic refactorings is to rename a class:

wwdc 2017

Notice the class itself is renamed, and all references to that class in the project are renamed as well, including references in the Storyboard and the filename itself! Sure, renaming something isn’t that tough, but you should lean on your IDE wherever possible to make your life easier.

There’s a bunch of other refactoring options available as well, and what’s even cooler is Apple will be open sourcing the refactoring engine so others can collaboratively extend and enhance it.

Swift 4

Xcode 9 comes with Swift 4 support by default. In fact, it has a single Swift compiler that can compile both Swift 3.2 and Swift 4, and can even support different versions of Swift across different targets in the same project!

We’ll be posting a detailed roundup about What’s New in Swift 4 soon.

Xcode ❤️s GitHub

Xcode 9 now connects easily with your GitHub account (GitHub.com, or GitHub Enterprise) making it very easy to see a list of your existing projects, clone projects, manage branches, use tags, and work with remotes.

Wireless Debugging

Xcode 9 no longer requires you to connect your debugging device to your computer via USB. Now you can debug your apps on real devices over your local network. This will also work with Instruments, Accessibility Inspector, Quicktime Player, and Console.

Simulator Enhancements

There’s some really neat changes to the iOS Simulator. Now you can run multiple simulators at once!

wwdc 2017

Yes, this is a screenshot I just took, and these are all different simulators running at the same time! In addition to each simulator being resizable, simulators also include a new bezel where you can simulate different hardware interactions that weren’t possible in the past.

Testing

There were two improvements to Xcode’s automated testing support that caught my eye:

  1. Xcode UI tests can access other apps – It hasn’t been possible in the past to write Xcode UI tests for app functionality that lives inside other apps, like Settings, or Extensions. It’s now possible for your Xcode UI tests to access other apps for providing deeper verification of behavior.

    For example, if your app leverages a Share Extension to receive photos, it was not possible to write an Xcode UI test to open the Share Sheet in the Photos app to share a picture into your app. This is now possible.

  2. Tests Can Run On Simulators In Parallel – Taking advantage of the ability to run more than one iOS Simulator at the same time, automated tests can now run on more than one simulator at the same time. For example, this will be useful for running your test suite against an iOS 10 Simulator while simultaneously running the same suite on an iOS 11 Simulator.

Speed

Several changes were made to Xcode that will speed up your app development process:

  • The Xcode team put some special effort into the Source Editor to ensure high performance editing for files of all sizes.
  • Xcode comes with a new build system with much improved speed. It’s beta so it’s off by default; be sure to enable in File->Workspace Settings.
  • Additionally, if you use Quick Open or the Search Navigator, you’ll see near-instantaneous results for whatever you are searching for.

iOS 11

iOS 11 was announced today and beta 1 is already available for download. There were several features that peaked my interest.

Drag and Drop

Perhaps the most exciting iOS enhancement for me was the introduction of drag and drop to the iPad. You can now drag and drop things from one place to another, whether it’s within a single app, or even across separate apps!

As a user, you can also take advantage of other advanced multitouch interactions to continue grabbing additional items to eventually send to the destination app. UITableView and UICollectionView make it pretty easy to add drag and drop to lists in your app.

Take a look at Apple’s drag and drop documentation for a section called First Steps to understand how to add drag and drop to your app.

ARKit

WWDC 2017 introduced ARKit, a framework that provides APIs for integrating augmented reality into your apps. On iOS, augmented reality mashes up a live view from the camera, with objects you programmatically place in the view. This gives your app’s users the experience their content is a part of the real world.

Augmented reality programming without some sort of help can be very difficult. As a developer you need to figure out where your “virtual” objects should be placed in the “reality” view, how the objects should behave, and how they should appear. This is where ARKit comes to the rescue and simplifies things for you the developer.

ARKit can detect “planes” in the live camera view, essentially flat surfaces where you can programmatically place objects so it appears they’re actually sitting in the real world, while also using input from the device’s sensors to ensure these items remain in the correct place. Apple’s article on Understanding Augmented Reality is a good place to start for learning more.

Machine Learning

Machine learning is an incredibly complicated topic. Luckily, the Core ML framework was released today to help make this advanced programming technique available to a wider audience. Core ML provides an API where developers can provide a trained model, some input data, and then receive predictions about the input data based on the trained model.

Right from their documentation on Core ML, Apple provides a good example use case for Core ML: predicting real estate prices. There’s a vast amount of historical data on real estate sales. This is the “model.” Once in the proper format, Core ML can use this historical data to make a prediction of the price of a piece of real estate based on data about the house, like the number of bedrooms (assuming the model data contains both the ultimate sale price, and the number of windows for a piece of real estate). Apple even supports trained models created with certain supported third party packages.

Vision

The iOS 11 SDK introduces the Vision framework. The Vision framework provides a way for you to do high performance image analysis inside your applications.

While face detection has been available already in the CoreImage framework, the Vision framework goes further by providing the ability to not only detect faces in images, but also barcodes, text, the horizon, rectangular objects, and previously identified arbitrary objects. The Vision framework also has the ability to integrate with a Core ML model. This allows you to create entirely new detection capabilities with the Vision framework.

For example, you could integrate a Core ML trained machine learning model to identify dogs drinking water in pictures (you just need to obtain the model first which helps the Vision framework understand how to look for a dog drinking water). Take a look at the Vision framework documentation for more information.

HEVC and HEIF

Support for two new media formats was introduced with iOS 11: High Efficiency Video Coding (HEVC) and High Efficiency Image Format (HEIF). These are contemporary formats that have improvements in compression, while also recognizing today’s image and video assets are more complicated than they were in the past. Technologies like Live Photos and burst photos require more information be kept for a given image.

For example, a Live Photo may designate a “key frame” to be the thumbnail to represent the sequence of images. These new formats provide a more convenient, and smaller, way to store and represent this data. The following frameworks have been updated to support these new formats: VideoToolbox, Photos, and Core Image.

MusicKit

I’m a huge fan of music, and I’m sad to say that I traded in my Apple Music subscription for a Spotify subscription about two months ago. The changes coming with the new MusicKit framework could single-handedly bring me back as a paying Apple Music customer. One of my biggest frustrations as an Apple Music customer was the lack of access to the streamable music from within third-party applications.

There isn’t much documentation on MusicKit yet, but Apple presented that there will now be programmatic access to anything in Apple Music. Not just songs the user owns, but all the streamable music.

AirPlay 2

And related to music, AirPlay 2 is also new with iOS 11. It’s most notable feature is the added ability to stream audio across multiple devices. Think Sonos, but with your AirPlay 2 supported devices!

In for your music or podcast playing app to take advantage of this, you’ll need to call setCategory(_:mode:routeSharingPolicy:options:) on AVAudioSession with the AVAudioSessionRouteSharingPolicyLongForm parameter value.

iOS Rapid Fire

There were a bunch of other miscellaneous updates that caught my eye as well:

  • App Store Redesign – Coming with iOS 11 is a redesigned App Store app. It looks a lot like Apple Music, and has separate tabs for Apps and Games.
  • Promote in-app purchases on the App Store – Got a new in-app purchase that you would like users aware of? You can now promote in-app purchases on the App Store, and additionally, in-app purchases can also be featured on the App Store by Apple!
  • Live Photo adjustments – You can now edit Live Photos to do things like loop the Live Photo, or blur the moving parts.
  • New SiriKit Domains and Intents – Enhancements to SiriKit now make it possible to add notes, interact with to-do lists and reminders, cancel rides, and transfer money.
  • Annotate Screenshots on iPad – When taking a screenshot on your iPad, you’ll be able to quickly access the screenshot via a thumbnail in the corner of the screen, and then annotate it with markup.
  • Phased App Releases – Now you can slowly release your app over a period of time. If you’re worried about a new app update putting a heavy load on your server-side backend, this can be a way to mitigate that risk.

Hardware

Another question we love to ask ourselves each WWDC is “what new hardware will we buy?” :]

HomePod

Apple’s response to the Amazon Echo and Google Home was announced today, HomePod. It follows suit as an Internet connected speaker that has an always-listening virtual assistant.

What was most interesting to me was that Siri was totally underplayed, and instead it was the musical and audio capabilities of the speaker that were highlighted. It was almost as if it’s advertised primarily as a listening device, and as a smart device second – which is opposite of the Amazon Echo and Google Home.

HomePod can also serve as your HomeKit hub. One thing of note is until you say “Hey Siri” the HomePod will not send any information to Apple.

Refreshed Desktops

iMacs and Macbook Pros were updated with contemporary hardware and new prices.

iMac Pro

Apple announced a brand new iMac Pro that will be available in December 2017.

New iPad Pro

A new 10.5″ iPad Pro was announced effectively replacing the 9.7″ iPad, while also providing newer capabilities.

WWDC 2017 Update