قالب وردپرس درنا توس
Home / IOS Development / What's new in Swift 5.1?

What's new in Swift 5.1?



Good news: Swift 5.1 is now available in Xcode 11 beta! This release provides module stability and enhances the language with important features. In this tutorial you will learn about what's new in Swift 5.1. You need Xcode 11 beta to work with Swift 5.1, so go ahead and install it before you get started.

Getting Started

Swift 5.1 is source compatible with Swift 5. There is also binary compatible with Swift 5 and future releases of Swift thanks to ABI stability .

Swift 5.1 adds module stability on top of ABI stability introduced in Swift 5. While ABI stability maintains application compatibility during runtime, module stability enables library compatibility at compile time. This means you can use a third-party framework with any compiler version instead of just the one it was built with.

Each tutorial contains Swift Evolution suggestions such as [SE-0001

]. You can explore each change by clicking the linked code for each suggestion.

I recommend you follow the tutorial by trying out the new features of a playground. Start Xcode 11 and go to File ▸ New ▸ Playground . Select iOS for the platform and Blank as template. Name it and save what you want. Time to get started!

Language Improvements

There are a number of language improvements in this release, including opaque result types, feature builders, property wrapping, and more.

Opake Result Types

You can use protocols as return types for features in Swift 5.

With your new playground open, open Project Navigator by navigating to View ▸ Navigators ators View Project Navigator . Right-click on the Sources folder select New File and name the file BlogPost . Replace the contents of the new file with the definition of a new protocol named BlogPost .

  public protocol BlogPost {
was titled: String {get}
was author: String {get}
}

Right-click on the top-level playground and select New Playground Page . Rename the new playground Opaque Tutorials and paste it into:

  // 1
struct Tutorial: BlogPost {
added title: String
Add Author: String
}

// 2
func createBlogPost (title: String, author: String) -> BlogPost {
guard! tittel.is tom &&! author.is even other {
fatalError ("No title and / or author assigned!")
}
return Tutorial (title: title, author: author)
}

// 3
la swift4Tutorial = createBlogPost (title: "What's new in Swift 4.2?",
author: "Cosmin Pupăză")
la swift5Tutorial = createBlogPost (title: "What's new in Swift 5?",
author: "Cosmin Pupăză")

Goes over this step by step:

  1. Explain title and author for Training since Training implementations BlogPost .
  2. Check if title and author are valid and return Tutorial from createBlogPost (title: author :) if successful.
  3. Use createBlogPost (title: author :) to create swift4Tutorial and swift5Tutorial .

You can use the prototype and logic of 1945 createBlogPost (title: author :) to create screens as well because screen casts are blog posts under the hood.

Right-click on the top-level playground and select New Playground Page . Rename the new playground Opaque Screencasts and paste it into:

  struct Screencast: BlogPost {
added title: String
Add Author: String
}

func createBlogPost (title: String, author: String) -> BlogPost {
guard! tittel.is tom &&! author.is even other {
fatalError ("No title and / or author assigned!")
}
return Screencast (title: title, author: author)
}

let swift4Screencast = createBlogPost (title: "What's new in Swift 4.2?",
author: "Josh Steele")
let swift5Screencast = createBlogPost (title: "What's new in Swift 5?",
author: "Josh Steele")

Screencast implements BlogPost to return Screencast from createBlogPost (title: author :) and uses createBlogPost ( title: author :) to create swift4Screencast and swift5Screencast this time.

Navigate to BlogPost.swift in Sources Folder and Layers BlogPost matches Equatable .

  public protocol BlogPost: Equatable {
was titled: String {get}
was author: String {get}
}

At this time, you get an error that BlogPost can only be used as a generic restriction. This is because Equatable has an associated type called Self . Protocols with associated types are not types, even though they look like types. Instead, they are the kind of like placeholders who say "this can be any specific type that complies with this protocol."

With Swift 5.1, you can use these protocols as regular types with opaque result types [SE-0244]. [19659004] On the Opaque Tutorials page, add some to the return type createBlogPost and say that it returns a concrete implementation of BlogPost .

  func createBlogPost (title: String, author: String) -> some BlogPost {

Similarly, in the Opaque Screencasts page, use some to tell the compiler createBlogPost return some type BlogPost . [19659013] func createBlogPost (title: String, author: String) -> some BlogPost {

You can return any specific type that implements BlogPost from createBlogPost : Tutorial or Screencast in this case.

Now, you can check if the previously created tutorials and screen casts are the same. At the bottom of the Opaque Tutorials paste the following to check if the swift4Tutorial and swift5Tutorial are the same.

  let sameTutorial = swift4Tutorial == swift5Tutorial

At the bottom of Opaque Screencasts paste the following to check if swift4Screencast and swift5Screencast are the same.

  let sameScreencast = swift4Screencast = swift5Screencast

Implicit Returns From Single-Expression Functions

You use return in single-expression functions in Swift 5:

  extension sequence where Element == Int {
func addEvenNumbers () -> Int {
return reduction (0) {$ 1.isMultiple (of: 2)? $ 0 + $ 1: $ 0}
}

func addOddNumbers () -> Int {
return reduction (0) {$ 1.isMultiple (of: 2)? $ 0: $ 0 + $ 1}
}
}

la tall = [10, 5, 2, 7, 4]
la evenSum = numbers.addEvenNumbers ()
la oddSum = numbers.addOddNumbers ()

You use reduce (_: _ :) in addEvenNumbers () and addOddNumbers () to determine the sum of even and odd numbers in Sequence .

Swift 5.1 drops return in single-expression functions, so they behave as single-line terminations in this case [SE-0255]:

  extension Sequence where Element == Int {
func addEvenNumbers () -> Int {
reduce (0) {$ 1.isMultiple (of: 2)? $ 0 + $ 1: $ 0}
}

func addOddNumbers () -> Int {
reduce (0) {$ 1.isMultiple (of: 2)? $ 0: $ 0 + $ 1}
}
}

The code is cleaner and easier to follow this time.

Function Builders

Swift 5.1 uses function builders to implement the build pattern [SE-XXXX]:

  @_ functionBuilder
struct SumBuilder {
static func buildBlock (_ number: Int ...) -> Int {
return tall.reduce (0, +)
}
}

Comment SumBuilder with @_ functionBuilder to make it a function type builder type. Function builders are special types of functions where each expression (letters, variable names, function calls, if statements, etc.) is handled separately and used to produce a single value. For example, you can write a function where each expression adds the result of the expression to an array, making your own type of letter literal.

Note : In Xcode beta, the Note for Function Builders @_ functionBuilder is because this proposal is not yet approved. When the approval comes, you can expect the note to be @functionBuilder .

You create feature builders by implementing various static functions with specific names and type signatures. buildBlock (_: T ...) is the only one needed. There are also features to handle if statements, options, and other structures that can be treated as expressions.

To use a function builder, comment on a function or termination with the class name:

  func getSum (@SumBuilder Builder: () -> Int) -> Int {
build ()
}

la gcd = getSum {
8
12
5
}

The closure that was given to getSum evaluates each expression (in this case the three numbers) and gives the list of those expressions results to the client. Function builders, along with implicit returns, are the building blocks of SwiftUI's pure syntax. They also let you create your own domain-specific languages.

Property Wrappers

You are dealing with quite a lot of boilerplate code when working with computed properties in Swift 5:

  var settings = ["swift": true, "latestVersion": true]

Structure Settings {
var isSwift: Bool {
get {
return settings ["swift"] ?? false
}
set {
settings ["swift"] = newValue
}
}

var isLatestVersion: Bool {
get {
return settings ["latestVersion"] ?? false
}
set {
settings ["latestVersion"] = newValue
}
}
}

var newSettings = Settings ()
newSettings.isSwift
newSettings.isLatestVersion
newSettings.isSwift = false
newSettings.isLatestVersion = false

isSwift and isLatestVersion get and enter the value of the given key in settings . Swift 5.1 removes the repetitive code by defining property wraps [SE-0258]:

  // 1
@propertyWrapper
struct SettingsWrapper {
leave key: String
la defaultValue: Bool

// 2
var wrappedValue: Bool {
get {
settings [key] ?? default
}
set {
settings [key] = newValue
}
}
}

// 3
Structure Settings {
@SettingsWrapper (key: "swift", defaultValue: false) was erSwift: Bool
@SettingsWrapper (key: "latestVersion", defaultValue: false)
var isLatestVersion: Bool
}

Here's how the code above works:

  1. Mark SettingsWrapper with @propertyWrapper to make it a type of wrapper type.
  2. Use wrappedValue to get and enter key in settings .
  3. Mark isSwift and isLatestVersion as @SettingsWrapper to implement them with similar packaging.
  Works with calculated properties in Swifty way!

Works with calculated properties in Swifty way!

Synthesizing Default Values ​​for Initializers in Structures

Swift 5 does not set the default properties for properties in structures by default, so you define custom initializers for them:

  struct Author {
name: String
var tutorialCount: Int

init (name: String, tutorialCount: Int = 0) {
self.name = name
self.tutorialCount = tutorialCount
}
}

let author = Author (name: "George")

Here you set tutorialCount to 0 if author has passed his trial period and joined the tutorial team on the site.

Swift 5.1 allows you to set default values ​​for structure properties directly, so no need for custom initializers anymore [SE-0242]:

  struct Author {
name: String
var tutorialCount = 0
}

The code is cleaner and simpler this time.

Even for static members

You cannot use Self to reference static members of a data type in Swift 5, so you must use the type name instead:

  struct Editor {
static func review Guidelines () {
print ("Review the editing policy.")
}

func editing () {
Editor.reviewGuidelines ()
print ("Ready to edit!")
}
}

let editor = editor ()
editor.edit ()

The editors of the site review the editing policies before editing any tutorials since they are always modified.

You can rewrite the whole thing using Self in Swift 5.1 [SE-0068]:

  struct Editor {
static func review Guidelines () {
print ("Review the editing policy.")
}

func editing () {
Self.reviewGuidelines ()
print ("Ready to edit!")
}
}

You use Self to call reviewGuidelines () this time.

Creating uninitialized arrays

You can create uninitialized arrays in Swift 5.1 [SE-0245]:

  // 1
la randomSwitches = Array  (unsafeUninitialisedCapacity: 5) {
buffer, count
// 2
for i in 0 .. <5 {
buffer [i] = Bool.random ()? "on off"
}
// 3
count = 5
} 

Go over the code above step by step:

  1. Use init (unsafeUninitialisedCapacity: initializingWith :) to create randomSwitches with a certain boot capacity.
  2. Loop through randomSwitches and specify each switch state with random () .
  3. Specify the number of initialized items for randomSwitches .

Diffing Ordered Orders

With Swift 5.1 you can determine the differences between ordered collections [SE-0240].

Let's say you have two matrices:

  let operatingSystems = ["Yosemite",
                        "El Capitan",
                        "Sierra",
                        "High Sierra",
                        "Mojave",
                        "Catalina"]
var answer = ["Mojave",
               "High Sierra",
               "Sierra",
               "El Capitan",
               "Yosemite",
               "Mavericks"]

operatingSystems contains all macOS versions since Swift 1 arranged from oldest to newest. answers list them in reverse order as you add and remove some of them.

Diffing collections require that you look for the latest Swift version with #if swift (> =) because all different methods are marked as @ available only for Swift 5.1:

  #if swift (> = 5.1)
let differences = operatingSystems.difference (from: answer)
la sameAnswers = answer. use (differences) ?? []
// ["Yosemite", "El Capitan", "Sierra", "High Sierra", "Mojave", "Catalina"]

Get differences between operatingSystems and answer with difference (from :) and use application (_ :) to use them on answers .

Alternatively, you can do this manually:

  // 1
for change in differences.inferringMoves () {
swap change {
// 2
case .insert (la offset, la element, la associated):
Answer.insert (element, on: offset)
guard la associatedWith = associated with other {
print (" (element) set to position  (offset + 1).")
break
}
print("""
 (element) moved from position  (associated with + 1) to position
 (offset + 1).
"" ")
// 3
case. remove (leave offset, leave element, leave associated with):
answer. remove (by: offset)
guard la associatedWith = associated with other {
print (" (element) removed from position  (offset + 1).")
break
}
print("""
 (element) removed from position  (offset + 1) because it should be
at position  (associated with + 1).
"" ")
}
}
# finally about

Here's how this code works:

  1. Use inferringMoves () to determine the movements of differences and loop through them.
  2. Add element to offset to answer if change is .set (offset: element: associated with: ) and treat the insert as a move if associated with is not zero .
  3. Delete element by shift from response if change is . Remove (offset: element: associated with :) and consider the removal as a move if associated with is not zero .
  Different collections as a pro in Swift 5.1!

Diffing collections like a pro in Swift 5.1!

Static and Class Description

With Swift 5.1 you can declare static and subscription in classes [SE-0254]:

  // 1
@dynamicMemberLookup
class File {
name: String

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

// 2
static subscription (key: string) -> string {
switch key {
case "path":
return "custom path"
default:
return "default path"
}
}

// 3
class instruction (dynamicMember key: String) -> String {
switch key {
case "path":
return "custom path"
default:
return "default path"
}
}
}

// 4
File ["path"]
File ["PATH"]
File.path
File.PATH

Here's how it works:

  1. Mark File as @dynamicMemberLookup to enable custom subscription dot syntax.
  2. Create a static subscription that returns the default or custom path for File .
  3. Define the class version of the previous subscription using dynamic membership lookup.
  4. Call both subscriptions with the corresponding syntax.

Keyboard Dynamic Member Lookup

Swift 5.1 implements Dynamic Keyboard Lookup [SE-0252]:

  // 1
structure Point {
la x, y: Int
}

// 2
@dynamicMemberLookup
struct Circle  {
la center: T
radius: Int

// 3
subscription  (dynamic member keyPath: KeyPath ) -> U {
center [keyPath: keyPath]
}
}

// 4
let center = point (x: 1, y: 2)
la circle = circle (center: center, radius: 1)
circle.x
circle.y

Goes over all this step by step:

  1. Explain x and y for Point .
  2. Annotate Circle with @dynamicMemberLookup to enable dot syntax for their signatures.
  3. Create a generic subscription that uses keyboards to access center properties from Circle . 19659018] Call center properties on circle using dynamic member lookup instead of keyboards.
Note : Need more information on how dynamic member lookups work in Swift? Take a look at the tutorial for dynamic features: Dynamic features in Swift.

Keypaths for Tuples

You can use keypaths for tuples in Swift 5.1:

  // 1
struct Instrument {
Note: String
la year: Int
leave details: (type: String, pitch: String)
}

// 2
la instrument = instrument (brand: "Roland",
year: 2019,
details: (type: "acoustic", pitch: "C"))
la type = instrument [keyPath: Instrument.details.type]
let pitch = instrument [keyPath: Instrument.details.pitch]

Here's what happens:

  1. Explain mark year and details for Instrument .
  2. Use keyboards to get type and pitch from details in instrument .

Equatable and Hashable Conformance for Weak and Unowned Properties

Swift 5.1 automatically synthesizes Equatable and Hashable conformity for structures with weak and stored properties.

Suppose you have two classes: [19659013] class key {
note: strict

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

extension Key: Hashable {
static func == (lhs: Key, rhs: Key) -> Bool {
lhs.note == rhs.note
}

func hash (for hasher: inout Hasher) {
hasher.combine (note)
}
}

class chord {
note: strict

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

extension chord: Hashable {
static func == (lhs: Chord, rhs: Chord) -> Bool {
lhs.note == rhs.note
}

func hash (for hasher: inout Hasher) {
hasher.combine (note)
}
}

Key and Chord both match Equatable and Hashable by implementing == (lhs: rhs: ) and hashish (to :) .

If you use these classes in a structure, Swift 5.1 will be able to synthesize Hashable conformity:

  struct Tune: Hashable {
unowned let key: Key
weak was chord: chord?
}

let key = key (note: "C")
la chord = Chord (brand: "C")
let tune = Tune (key: key, chord: chord)
light chordlessTune = Tune (key: key, chord: nil)
la sameTune = tune == chordlessTune
la tuneSet: Set = [tune, chordlessTune]
la tuneDictionary = [tune: [tune.key.note, tune.chord?.note],
chordlessTune: [chordlessTune.key.note, 
                      chordlessTune.chord?.note]]

Tune is Equatable and Hashable because key and chord are Equatable and Hashable .

Because it is Hashable you can compare tune with chordlessTune add them to tuneSet and use them as keys for tuneDictionary .

Ambiguous enumeration cases

Swift 5.1 generates warnings for ambiguous enumeration cases:

  // 1
enum TutorialStyle {
case cookbook, stepByStep, none
}

// 2
la style: TutorialStyle? =. no

Here's how it works:

  1. Define different styles for TutorialStyle .
  2. Swift fires a warning since it is not clear to the compiler what . No in this case means: Optional.none or TutorialStyle.none .

Matching optional enumerations against non-optional selections

You use optional pattern to match non-optional selections with optional enumerations in Swift 5:

  // 1
enum TutorialStatus {
case written, edited, published
}

// 2
la status: TutorialStatus? = .published

switch status {
case. written ?:
print ("Ready to edit!")
case. edited?:
print ("Ready to Publish!")
case .published?:
out ("Live!")
case. no:
break
}

The code above does the following:

  1. Declare all possible states for TutorialStatus .
  2. Use the optional pattern to turn on status since you define it as optional.

Swift 5.1 removes optional pattern matching in this case:

  switch status {
case. written:
print ("Ready to edit!")
case. edited:
print ("Ready to Publish!")
case .published:
out ("Live!")
case. no:
break
}

The code is cleaner and easier to understand this time.

New strings functions

Swift 5.1 adds some much-needed functions to the strings [SE-0248]:

  UTF8.width ("S")
UTF8.isASCII (83)

Here you determine the UTF-8 encoding width to the Unicode scalar value and check if the given encoder represents an ASCII scalar. Take a look at the suggestion of other APIs you can use.

Contiguous Strings

Swift 5.1 implements important changes to continuous strings [SE-0247]:

  var string = "Swift 5.1"
if! string.isContiguousUTF8 {
string.makeContiguousUTF8 ()
}

You check if the encoded string UTF-8 is related to isContiguousUTF8 and uses makeContiguousUTF8 () to do so, if not. Take a look at the proposal to see what else you can do with continuous strings.

Various bits and pieces

There are some other features of Swift 5.1 you should know about:

Converting tuple types

Swift 5.1 improves conversion of tuple types:

  let temperatures: (Int, Int) = (25, 30)
let converter temperature: (Int?, any) = temperatures

You assign temperatures to converted temperatures because you can convert (Int, Int) to (Int?, Some) in this case.

Tuples with Duplicate Labels

You can declare duplicate labels in Swift 5:

  easy point = (coordinate: 1, coordinate: 2)
point.coordinate

It is not clear whether coordinate returns the first or second element from point in this case, so Swift 5.1 removes duplicate labels for tuples.

Overload functions with some parameters [19659011] Swift 5 prefers Any parameters instead of generic arguments for overloading functions with only one parameter:

  func showInfo (_: Any) -> String {
return "Any value"
}

func showInfo  (_: T) -> String {
return "Generic Value"
}

showInfo ("Swift 5")

showInfo () returns "Any value" in this case. Swift 5.1 works the other way around:

  func showInfo (_: Any) -> String {
"Any value"
}

func showInfo  (_: T) -> String {
"Generic value"
}

showInfo ("Swift 5.1")

showInfo () returns "Generic Value" this time.

Type aliases for autoclosure Parameters

You cannot declare type aliases for @autoclosure parameters in Swift 5:

  struct Closure  {
func Apply (closure: @autoclosure () -> T) {
closing device ()
}
}

applies (closure :) uses autocausing signature for closure in this case. You can use type aliases in the prototype of Apply (closure :) in Swift 5.1:

  struct Closure  {
typealias ClosureType = () -> T

func Apply (closure: @autoclosure ClosureType) {
closing device ()
}
}

search (closure :) uses ClosureType for closure this time.

Returning Self From Object-C Methods

You must inherit from NSObject if your class contains a @objc method that returns Self in Swift 5:

  class Clone: ​​NSObject {
@objc func clone () -> Even {
return yourself
}
}

Clone extends NSObject because clone () returns Self . This is no longer the case in Swift 5.1:

  class Clone {
@objc func clone () -> Even {
self
}
}

Clone need not inherit from anything this time.

Stable ABI Libraries

You use -enable-library-evolution in Swift 5.1 to make changes to library types without breaking the ABI. Structures and enumerations labeled as @frozen cannot add, remove, or reorganize stored properties and cases [SE-0260].

Where to Go From Here?

You can download the final playground using the Download Materials link at the top or bottom of this tutorial.

Swift 5.1 adds many nice features to those already introduced in Swift 5. It also brings module stability to the language and implements complex paradigms used by new frameworks introduced on WWDC such as SwiftUI and Combine.

You can read more about the changes in this Swift version on the official Swift CHANGELOG or Swift standard library differences.

You can also look at the Swift Evolution suggestions to see what's coming in the next version of Swift. Here you can give feedback on suggestions that are currently being reviewed, and even make a suggestion yourself!

What is your favorite Swift 5.1 feature so far? Let us know in the forum discussion below!


Source link