Also Read:Swift 3.1: Swift Package Manager – Part 2
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-- class Student {
- let name: String
- let grade: Int
- init?(json: [String: Any]) {
- guard let name = json[“name”] as? String,
- let gradeString = json[“grade”] as? String,
- let gradeDouble = Double(gradeString),
- let grade = Int(exactly: gradeDouble) // <– 3.1 feature here
- else {
- return nil
- }
- self.name = name
- self.grade = grade
- }
- }
- func makeStudents(with data: Data) -> [Student] {
- guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
- let jsonArray = json as? [[String: Any]] else {
- return []
- }
- return jsonArray.flatMap(Student.init)
- }
- let rawStudents = “[{\”name\”:\”Ray\”, \”grade\”:\”5.0\”}, {\”name\”:\”Matt\”, \”grade\”:\”6\”},
- {\”name\”:\”Chris\”, \”grade\”:\”6.33\”}, {\”name\”:\”Cosmin\”, \”grade\”:\”7\”},
- {\”name\”:\”Steven\”, \”grade\”:\”7.5\”}]”
- let data = rawStudents.data(using: .utf8)!
- let students = makeStudents(with: data)
- dump(students) // [(name: “Ray”, grade: 5), (name: “Matt”, grade: 6), (name: “Cosmin”, grade: 7)]
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.Also Read:Kotlin- The Next-Gen Android App Development Language
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:- let fibonacci = sequence(state: (0, 1)) {
- (state: inout (Int, Int)) -> Int? in
- defer {state = (state.1, state.0 + state.1)}
- return state.0
- }
- // Swift 3.0
- for number in fibonacci.prefix(10) {
- print(number) // 0 1 1 2 3 5 8 13 21 34
- }
- // Swift 3.1
- let interval = fibonacci.prefix(while: {$0 < 1000}).drop(while: {$0 < 100})
- for element in interval {
- print(element) // 144 233 377 610 987
- }
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:- // Swift 3.0
- extension String {
- var isBlank: Bool {
- return trimmingCharacters(in: .whitespaces).isEmpty
- }
- }
- let abc = ” “
- let def = “x”
- abc.isBlank // true
- def.isBlank // false
- // Swift 3.0
- protocol StringProvider {
- var string: String {get}
- }
- extension String: StringProvider {
- var string: String {
- return self
- }
- }
- extension Optional where Wrapped: StringProvider {
- var isBlank: Bool {
- return self?.string.isBlank ?? true
- }
- }
- let foo: String? = nil
- let bar: String? = ” “
- let baz: String? = “x”
- foo.isBlank // true
- bar.isBlank // true
- baz.isBlank // false
- // Swift 3.1
- extension Optional where Wrapped == String {
- var isBlank: Bool {
- return self?.isBlank ?? true
- }
- }
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-- class Team<T> {
- enum TeamType {
- case swift
- case iOS
- case macOS
- }
- class BlogPost<T> {
- enum BlogPostType {
- case tutorial
- case article
- }
- let title: T
- let type: BlogPostType
- let category: TeamType
- let publishDate: Date
- init(title: T, type: BlogPostType, category: TeamType, publishDate: Date) {
- self.title = title
- self.type = type
- self.category = category
- self.publishDate = publishDate
- }
- }
- let type: TeamType
- let author: T
- let teamLead: T
- let blogPost: BlogPost<T>
- init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost<T>) {
- self.type = type
- self.author = author
- self.teamLead = teamLead
- self.blogPost = blogPost
- }
- }
- Team(type: .swift, author: “Cosmin Pupăză”, teamLead: “Ray Fix”,
- blogPost: Team.BlogPost(title: “Pattern Matching”, type: .tutorial,
- category: .swift, publishDate: Date()))
- Team(type: .swift, author: “Cosmin Pupăză”, teamLead: “Ray Fix”,
- blogPost: Team.BlogPost(title: “What’s New in Swift 3.1?”, type: .article,
- category: .swift, publishDate: Date()))
- class Team<T> {
- // original code
- class BlogPost {
- // original code
- }
- // original code
- let blogPost: BlogPost
- init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost) {
- // original code
- }
- }
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-- func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void,
- on queue: DispatchQueue) {
- withoutActuallyEscaping(f) { escapableF in // 1
- withoutActuallyEscaping(g) { escapableG in
- queue.async(execute: escapableF) // 2
- queue.async(execute: escapableG)
- queue.sync(flags: .barrier) {} // 3
- } // 4
- }
- }
- f and g come in as non-escaping and are converted to escapableF and escapableG.
- async(execute:) calls require escaping closures. Fortunately, you have those because of the previous step.
- By running sync(flags: .barrier), you ensure that the async(execute:) methods are completely done and the closures won’t be called later on.
- Scope limits the use of escapableF and escapableG.
Join Us