What’s new Swift 4.2?

The latest update of Swift 4.2 came out last week at WWDC, and it has some pretty exciting improvements.

Some had me thinking ‘that’ll be useful’, some had me excited and some, to be honest, had me thinking ‘FINALLY!’ Here are some of my highlights:

Random

giphy.gif

One feature that I’m especially pleased about is random. Random has always been a sticking point for me in Swift – arc4random, arc4random_uniform, and drand48  have seemed out of place – more like an artifact from ancient history than a part of a ‘modern’ language, and in fact, they were! These methods directly accessed lower level C APIs.

arc4random and arc4random_uniform used and returned the little used UInt32 type (Int and UInt are much more common in Swift, which automatically uses either the 32 or 64 bit version depending on the platform your app is running on.) This means that the parameter being passed and the response always had to be converted, making a request for random extra verbose. Want a random integer between 0 and 10? Take a look at this:

let max = 10
//pre Swift 4.2
let result = Int(arc4random_uniform(UInt32(max)))

Wow. See what I mean? And if the laborious syntax isn’t a convincing enough reason – arc4random didn’t return uniform distribution of random numbers, drand48 (though it did return more useful data type Double) required an additional step of seeding, and let’s be honest – these methods had horribly ugly names!

Well – breathe a sigh of relief because Swift 4.2 has a new and exciting API with a whole range of convenience methods to make our lives easier as developers.

Remember the random integer between 0 and 10? How about this:

let max = 10
//Swift 4.2
let result = Int.random (in: 0 ..< max)

Much simpler and more readable, right? And it doesn’t have to be an integer, all numeric types have a random method now – here’s the Double version:

let max = 10
//Swift 4.2
let result = Double.random (in: 0 ..< max)

There are even collection convenience methods that select a random element.
Want to pick a suit, any suit? Too easy now:

var suits = ["Hearts","Diamonds","Clubs","Spades"]
//Swift 4.2
let suit = suits.randomElement()!

Want to shuffle the suits? Just as easy:

//Swift 4.2
suits.shuffle()

You can check out the Swift Evolution proposal for random unification here.

Bool toggle

Speaking of neat little convenience methods, here’s another!

You can now simply call the toggle method on a boolean.

No more:

//pre Swift 4.2
soundOn = !soundOn

You can now do this:

//Swift 4.2
soundOn.toggle()

You can check out the Swift Evolution proposal for adding toggle to Bool here.

New Collection higher order functions

When higher order functions come up, people often discuss the big four – map, filter, reduce and sort. In my post on higher order functions in Swift, I looked at a whole bunch of other higher order functions that collection types offer. Well, in Swift 4.2 we have more!

allSatisfy

Whereas the contains method returns a Bool based on whether at least one element in a collection satisfies a condition, the new allSatisfy method returns a Bool based on whether all elements satisfy a condition. For example:

var fruits = ["Banana","Banana","Coconut","Banana","Banana","Banana"]
//Swift 4.2
let completelyBananas = fruits.allSatisfy { $0 == "Banana" } //false

Check out the SE proposal here.

First and last

We previously had methods index(of:) and index(where:) which found the first item which satisfied a condition. We now have lastIndex(of:) and lastIndex(where:) too, which finds the last item in the collection that satisfies a condition. It made sense then to change the name of the index methods to firstIndex(of:) and firstIndex(where:).

You can find the SE proposal for first and last methods here.

Remove all

Remember the confusion you had when you first tried to remove all items from an array that satisfied a condition using a simple for loop?
You may have programmed something like:

var fruits = ["Banana","Banana","Coconut","Banana","Banana"]
//remove all bananas (naive implementation)
for (index,fruit) in fruits.enumerated() {
  if fruit == "Banana" {
    fruits.remove(at: index)
  }
}

Then everything really did go bananas when an Index out of Range error appeared in the console?

Oopsbutton.jpg

Ah for more innocent days.

Of course the index had continued to increment while the number of elements in the array steadily decreased, until finally the loop index was higher than the number of elements in the array, causing a crash. There were solutions to this problem of course – loop in reverse, for example, or use the filter method, but now we have a method built for just this task, removeAll. Take a look:

var fruits = ["Banana","Banana","Coconut","Banana","Banana"]
//remove all bananas (Swift 4.2)
fruits.removeAll { $0 == "Banana" }

Well,​ that was easier! You can find the SE proposal for remove all collection method here.

Looping through enumerations

I remember years ago having an enumeration nicely set up – I think it was something like an enum for card suits…

enum Suit {
  case hearts
  case diamonds
  case clubs
  case spades
}

…and I remember realizing I needed to loop through the cards. (Perhaps it was to find a random suit) I remember thinking – well that shouldn’t be so hard, I already have the enum set up, right?

I then realized that this isn’t a default feature of enums, and I remember thinking, “whaaa?”

Pp9rx.gif

Of course,​ there was a way around this – you could set up a static variable for example that contained an array of all the items in the enum:

//pre Swift 4.2
enum Suit {
  case hearts
  case diamonds
  case clubs
  case spades
  static var allCases:[Suit] = [.hearts, .diamonds, .clubs, .spades]
}

You could then use this allCases property to loop through the cases:

for suit in Suit.allCases {
  print(suit)
}

Well, Swift 4.2 (FINALLY!) can automatically synthesize this for you. All you need to do is adopt the CaseIterable protocol.

//Swift 4.2
enum Suit:CaseIterable {
  case hearts
  case diamonds
  case clubs
  case spades
}

Imagine – combined with the new collection convenience methods, we could now shuffle your enum case suits:

//Swift 4.2
var suitsShuffled = Suit.allCases.shuffled()

Or pick a random suit!

//Swift 4.2
var pickASuitAnySuit = Suit.allCases.randomElement()!

Wow! You can find the SE proposal for the all cases property for enums here.

Well – that’s plenty to be excited about with Swift 4.2, and I haven’t even covered everything new! If you’re interested in reading about other proposals I haven’t mentioned that made it into Swift 4.2 or perhaps are on their way for Swift 5, you can take a look over at the Swift Evolution page.

iOS development with Swift - book: https://manning.com/books/ios-development-with-swift video course: https://www.manning.com/livevideo/ios-development-with-swift-lv

Tagged with: , , , ,
Posted in Swift

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: