How Swift 3.1 is different from earlier version? – Part 1

As most of the developers know that Swift is a general-purpose programming language. It is built using a modern approach to safety, performance, and software design patterns. And if you are already an iOS developer, you are already familiar with these things! Recently, a beta version of Xcode 8.3 and Swift 3.1 was released with Swift Package Manager features and improvements to the language. In this article we will majorly discuss about the Language improvements, rest will be covered in other part of the article. Let us check out the most significant features and changes in Swift 3.1 as it will have a major impact on your code!

Introduction

Swift 3.1 has downward compatibility, a person can work on lower versions codes of Swift. All you need to do is to migrate your project to Swift 3.0 using Edit\Convert\To Current Swift Syntax in Xcode. Start Xcode, select File-> New-> Playground. Choose iOS as the platform, you can call it whatever you want, and save it wherever you want.

Language Improvements

There are a number of languages improvements in this release. It includes failable initializers for numeric types, new sequence functions, and more. Let us check them out-

1. Failable Numeric Conversion Initializers

The new version implements failable initializers for all numeric types such as Int, UInt, Float, Double, etc. It either completes successfully without losing any information or simply returns NIL. This feature helps while dealing with loosely typed data conversion from external sources in a safe and recoverable manner. Just check it out by processing this JSON code-
  1. class Student {
  2.  let name: String
  3.  let grade: Int
  4.  
  5.  init?(json: [String: Any]) {
  6.    guard let name = json[“name”] as? String,
  7.          let gradeString = json[“grade”] as? String,
  8.          let gradeDouble = Double(gradeString),
  9.          let grade = Int(exactly: gradeDouble)  // <– 3.1 feature here
  10.    else {
  11.        return nil
  12.    }
  13.    self.name = name
  14.    self.grade = grade
  15.  }
  16. }
  17. func makeStudents(with data: Data) -> [Student] {
  18.  guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
  19.        let jsonArray = json as? [[String: Any]] else {
  20.    return []
  21.  }
  22.  return jsonArray.flatMap(Student.init)
  23. }
 
  1. let rawStudents = “[{\”name\”:\”Ray\”, \”grade\”:\”5.0\”}, {\”name\”:\”Matt\”, \”grade\”:\”6\”},
  2.                    {\”name\”:\”Chris\”, \”grade\”:\”6.33\”}, {\”name\”:\”Cosmin\”, \”grade\”:\”7\”},
  3.                    {\”name\”:\”Steven\”, \”grade\”:\”7.5\”}]”
  4. let data = rawStudents.data(using: .utf8)!
  5. let students = makeStudents(with: data)
  6. dump(students) // [(name: “Ray”, grade: 5), (name: “Matt”, grade: 6), (name: “Cosmin”, grade: 7)]
Here, failable initializer is used to convert the grade property from Double to Int inside the Student class.
let grade = Int(exactly: gradeDouble)
If gradeDouble is a fractional value, it will fail. It will succeed only if the value can be represented exactly as an integer.

2. New Sequence Functions

There are two new functions for data filtering to the standard library’s Sequence protocol- prefix(while:) and drop(while:). Consider the Fibonacci infinite sequence:
  1. let fibonacci = sequence(state: (0, 1)) {
  2.  (state: inout (Int, Int)) -> Int? in
  3.  defer {state = (state.1, state.0 + state.1)}
  4.  return state.0
  5. }
  Swift 3.0 simply specify the iteration count to iterate through the Fibonacci sequence-
  1. // Swift 3.0
  2. for number in fibonacci.prefix(10) {
  3.  print(number)  // 0 1 1 2 3 5 8 13 21 34
  4. }
Swift 3.1 lets you use prefic(while:) and drop(while:) with a condition to get all the elements of the sequence between two given values.
  1. // Swift 3.1
  2. let interval = fibonacci.prefix(while: {$0 < 1000}).drop(while: {$0 < 100})
  3. for element in interval {
  4.  print(element) // 144 233 377 610 987
  5. }
In the code, prefix(while:) returns the longest sub-sequence which satisfies a certain predicate. while drop(while:) does the opposite.  

3. Concrete Constrained Extensions

Swift 3.1 extended generic type with a concrete type constraint. Previously, it could not extend a type like this due to protocol constraint. Example- Ruby on Rails provides isBlank method for checking for user input. Let us check out how it would be implemented in Swift 3.0 as a computed property on the String data type extension:
  1. // Swift 3.0
  2. extension String {
  3.  var isBlank: Bool {
  4.    return trimmingCharacters(in: .whitespaces).isEmpty
  5.  }
  6. }
  7. let abc = ” “
  8. let def = “x”
  9. abc.isBlank // true
  10. def.isBlank // false
If you want the isBlank computed property to work with optional strings as well, you would do the following in Swift 3.0:
  1. // Swift 3.0
  2. protocol StringProvider {
  3.  var string: String {get}
  4. }
  5. extension String: StringProvider {
  6.  var string: String {
  7.    return self
  8.  }
  9. }
  10. extension Optional where Wrapped: StringProvider {
  11.  var isBlank: Bool {
  12.    return self?.string.isBlank ?? true
  13.  }
  14. }
  15. let foo: String? = nil
  16. let bar: String? = ”  “
  17. let baz: String? = “x”
  18. foo.isBlank // true
  19. bar.isBlank // true
  20. baz.isBlank // false
Swift 3.1 lets you extend a concrete type instead of a protocol like this:
  1. // Swift 3.1
  2. extension Optional where Wrapped == String {
  3.  var isBlank: Bool {
  4.    return self?.isBlank ?? true
  5.  }
  6. }
It is better than earlier versions because it does the same work in fewer lines.

4. Nested Generics

The new version allows you to mix nested types with generics. Understanding it with an example would be easier when an article is posted on a website, the actual coding behind looks like this-
  1. class Team<T> {
  2.  enum TeamType {
  3.    case swift
  4.    case iOS
  5.    case macOS
  6.  }
  7.  
  8.  class BlogPost<T> {
  9.    enum BlogPostType {
  10.      case tutorial
  11.      case article
  12.    }
  13.    
  14.    let title: T
  15.    let type: BlogPostType
  16.    let category: TeamType
  17.    let publishDate: Date
  18.    
  19.    init(title: T, type: BlogPostType, category: TeamType, publishDate: Date) {
  20.      self.title = title
  21.      self.type = type
  22.      self.category = category
  23.      self.publishDate = publishDate
  24.    }
  25.  }
  26.  
  27.  let type: TeamType
  28.  let author: T
  29.  let teamLead: T
  30.  let blogPost: BlogPost<T>
  31.  
  32.  init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost<T>) {
  33.    self.type = type
  34.    self.author = author
  35.    self.teamLead = teamLead
  36.    self.blogPost = blogPost
  37.  }
  38. }
  We nest BlogPost inner class within Team outer class and make both classes generic. And this is how it looks like-
  1. Team(type: .swift, author: “Cosmin Pupăză”, teamLead: “Ray Fix”,
  2.     blogPost: Team.BlogPost(title: “Pattern Matching”, type: .tutorial,
  3.     category: .swift, publishDate: Date()))
  4. Team(type: .swift, author: “Cosmin Pupăză”, teamLead: “Ray Fix”,
  5.     blogPost: Team.BlogPost(title: “What’s New in Swift 3.1?”, type: .article,
  6.     category: .swift, publishDate: Date()))
  Whereas it could be simplified. Nested inner type can inherit the parent’s class type by default if the nested inner type uses the generic outer one. Therefore you don’t have to declare it, like so:
  1. class Team<T> {
  2.  // original code
  3.  
  4.  class BlogPost {
  5.    // original code
  6.  }  
  7.  
  8.  // original code
  9.  let blogPost: BlogPost
  10.  
  11.  init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost) {
  12.    // original code   
  13.  }
  14. }

5. Convert Non-Escaping Closures to Escaping Ones

In Swift 3.0, closure arguments were made non-escaping to function by default, while you can convert non-escaping closures to escaping ones temporarily by using withoutActuallyEscaping() helper function in Swift 3.1. Let us understand this with an example-
  1. func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void,
  2.             on queue: DispatchQueue) {
  3.  withoutActuallyEscaping(f) { escapableF in     // 1
  4.    withoutActuallyEscaping(g) { escapableG in
  5.      queue.async(execute: escapableF)           // 2
  6.      queue.async(execute: escapableG)     
  7.      queue.sync(flags: .barrier) {}             // 3
  8.    }                                            // 4
  9.  }
  10. }
This function runs two closures simultaneously and then returns when both are done.
  1. f and g come in as non-escaping and are converted to escapableF and escapableG.
  2. async(execute:) calls require escaping closures. Fortunately, you have those because of the previous step.
  3. By running sync(flags: .barrier), you ensure that the async(execute:) methods are completely done and the closures won’t be called later on.
  4. Scope limits the use of escapableF and escapableG.
If you squirrel either temporary escaping closures away (i.e. actually escaped them) it would be a bug. There are many other changes in Swift 3.1. They include Swift Package Manager Updates, Multiple-Return Functions, Disable Auto-Linking, etc. We will be discussing it in next part. Till then share your views with use!