Swift 4, Review the New - Part Two

20 November, 2017

AleksandrPavliuk

On September 19, 2017, Apple announced release of Swift 4.0 on the official blog of Swift language. We've started discussing the changes it brought in Swift 4, Review the New - Part One. Let's see what else Swift 4.0 has for us.

1. Dictionary and Set Updates

Dictionary from Sequence

New Dictionary initializer from Sequence of key-value pairs added [SE-0165]:

You can specify a default value, it will return for missing keys of the subscript argument, important feature is that the returning type is non-optional.

newDictionary[5, default: "not found"]

Dictionary-Specific Map and Filter

filter and map methods are very powerful tools for developers. But it was awkward to have Array as a return type after applying this methods to Dictionary and Set. From now, filter for Dictionary returns Dictionary, and mapValues works similarly - keeps the dictionary structure during the change of values:

let filtered = newDictionary.filter {

$0.key % 2 == 0

}

// [2: "Gregor"]

let mapped = newDictionary.mapValues { value in

value.uppercased()

}

// [2: "GREGOR", 3: "KATE", 1: "IVAN"]

filter for Set returns a Set and not an Array:

let set: Set = [1,2,3,4,5]

let filteredSet = set.filter { $0 % 2 == 0 }

type(of: filteredSet) // Set<Int>

Grouping a Sequence

A very cool and useful feature is an ability to group sequences into buckets:

2. MutableCollection.swapAt(_:_:)

In [SE-0173] introduced is a new swapAt method for MutableCollection, which does a very easy job: taking two indices and swapping appropriate elements:

var numbers = [1,2,3,4,5]

numbers.swapAt(0,1)

numbers// [2, 1, 3, 4, 5]

Unlike swap method, which manipulates inout arguments, the last one is marked as deprecated.

3. Reduce with inout

New variant of reduce function was added to the standard library. In this variant, partial result becomes inout, which is passed to the combine function as before [SE-0171]:

extensionSequencewhere Iterator.Element: Equatable {

func uniq() -> [Element] {

returnreduce(into: []) { (result: inout [Element], element) in

if !result.contains(element) {

result.append(element)

}

}

}

}

[1,2,3,2,4,6,1,6].uniq() // [1, 2, 3, 4, 6]

Motivation to do this is to make reduce faster. The previous version of reduce makes copies of result for each element of a sequence, preventing this leads to performance boost.

4. Generic Subscripts

Subscripts now can have generic arguments and a return type [SE-0148]. A good use case is to make a type that represents JSON. With a generic subscript you can define an expected return type:

struct JSON {

fileprivate var storage: [String: Any]

init(dictionary: [String: Any]) {

self.storage = dictionary

}

subscript<T>(key: String) -> T? {

returnstorage[key] as? T

}

}

let json = JSON(dictionary: [

"name": "Berlin",

"country": "de",

"population": 3_500_500

])

// No need to use as? Int

let population: Int? = json["population"]

5. Improved integers

[SE-0104] was originally accepted for Swift 3, but was implemented only in Swift 4 in a slightly revised version. As official documentation states “this proposal cleans up Swifts integer APIs and makes them more useful for generic programming.” The new protocols come into play once you want to write generic algorithms that work on multiple numeric types. You can now compare Int and UInt without explicit conversion:

let a: Int = 5

let b: UInt = 5

let c: Int8 = -10

a == b// doesn't compile in Swift 3

a > c// doesn't compile in Swift 3

You can make arithmetic with overflow reporting:

let (partialValue, overflow) = Int32.max.addingReportingOverflow(1)

partialValue// -2147483648

overflow// true

And much more fun. Read the proposal [SE-0104] to get the full picture.

6. NSNumber Bridging

In Swift 3, some buggy behavior takes place during casting NSNumber to swift number types, fortunately this is fixed by [SE-0170]:

let n = NSNumber(value: UInt32(543))

let v = nas? Int8// nil in Swift 4. This would be 31 in Swift 3.

7. Associated type constraints

The associated type can now be constrained with where clauses [SE-0142]:

8. Limiting @objc inference

Swift 4 no longer automatically infers a declaration to be @objc in many places like it was earlier. Now you'll need to use @objc explicitly in situations where you want the full dynamic dispatch capabilities of Objective-C [SE-0160].

@objcMembers

You can use a new @objcMembers attribute to class declaration if you want to expose all your classes to Objective-C.

Dynamic Doesn’t Imply @objc

Note that dynamic doesn’t imply @objc anymore, you need to add @objc dynamic to a declaration. It’s what you need to check in your projects during migration to new Swift.

9. Composing classes and protocols

Now you can create a variable of a specific type that is constrained to one or more protocols [SE-0156]:

classSomeClass {}

protocolProtocol1 {}

protocolProtocol2 {}

extensionSomeClass: Protocol1 {}

extensionSomeClass: Protocol2 {}

let variable: SomeClass & Protocol1 & Protocol2 = SomeClass()

Conclusion

Presented in Swift 4, Review the New - Part One and here are all changes that Swift 4 presents. Swift becomes more and more friendly and pretty looking. More information you can find at these beautiful resources:

Thank you for reaching out to Sigma Software! Please fill the form below. Our team will contact you shortly.

Full Name *

E-mail *

Phone

Company

Message

Page url

I hereby confirm that I am familiar with
Sigma Privacy Policy and agree to the personal data provided by me being stored and processed in accordance with the Policy
*

Aleksandr

Pavliuk

iOS Developer

Aleksandr is an experienced iOS Developer and an enthusiast of Swift. He has solid understanding of the mobile development process and tunes into emerging technologies, trends, and events in the field.