The book “Swift. Basics of developing applications for iOS, iPadOS and macOS. 6th ed. supplemented and revised “

image Hello Habitants! The Swift language is simple, straightforward and perfect for both beginners and experienced programmers. All you need to start writing code is this book, a computer, and a willingness to learn. All basic programming concepts and basic syntax are explained in accessible language, so if you’ve never done any development before, then this book is a great start. Theory alternates with practical examples and code, so you can immediately connect abstract concepts to real situations. Each chapter has quizzes and homework assignments to help you solidify the material.

Corrections in the sixth edition

Compared to the previous edition, this book contains the following changes and additions:

The book format has been changed (it is now larger and thicker).
The tutorial has been updated for Swift 5.3 and Xcode 12.
Most of the chapters in the book have been rewritten and updated.
Added new material that was not previously included in the book:

An example of using the SwiftUI framework.
The choice between classes and structures.
About protocol-oriented programming.
About the numeric data type Decimal.
About the keyword some.
How ARC works and storing value type and reference type in memory.
About new methods for working with arrays.

Added sections “What to use it for”, which briefly show what in real projects the studied possibilities can be used.
Sets have been renamed to sets.

Updated graphic materials (diagrams, pictures, graphs and screenshots).

The found typos have been corrected and the wishes and comments of readers regarding the design and content have been taken into account.

Book structure

You have already started your journey into the world of Swift. You will soon be taking the first mandatory steps before developing your own applications. You will learn how to create your own Apple ID, how to connect to the Apple Developer Program, where to get a Swift development environment and how to work with it.

All subsequent material in the book is divided into six parts:

Part I. Basic features of Swift. After getting familiar with the Xcode development environment, you will learn the basic features of Swift. You will learn what syntax Swift has, what variables and constants are, what data types exist, and how to use all of this when developing programs.

Part II. Container data types. What are Sequences and Collections, and how important are they to building your programs? In this part of the book, you will learn about the most important elements of the programming language.

Part III. Key features of Swift. The third part focuses on reviewing and exploring the simplest, but very interesting Swift tools that allow you to control the flow of application execution.

Part IV. Introduction to Application Development. This part focuses on learning the basics of the Xcode development environment, as well as building the first two console applications.

Part V. Non-trivial features of Swift. The fifth part describes in detail how to work with the most powerful and functional features of Swift. You will use the material in this part with enviable regularity when creating your own applications in the future. There is also a lot of hands-on work ahead of you – creating your first interactive application in the Xcode Playground.

Part VI. An introduction to iOS development. At the end of a long and exciting journey of learning a language and creating simple applications, you will plunge into the world of full-fledged software development. In this part, you will learn the basics of creating interfaces and running programs in Xcode under the hood. All this in the future will allow you to successfully master new material and create wonderful projects.

Initializers and Deinitializers

An initializer (constructor) is a special method that prepares an instance of an object data type. The initializer fires when an instance is created, and when it is deleted, the deinitializer is called.

27.1. Initializers

The initializer sets up the initial values ​​for the stored properties and various settings that are required to use the instance.

Designated initializers

When implementing your own data types, in many cases you do not need to create your own initializer, since classes and structures have built-in initializers:

– classes have an empty built-in init () {} initializer;
– structures have a built-in initializer that takes the values ​​of all properties as input arguments.

An empty initializer works without errors only if the class has no properties or if each property has a default value.
For optional data types, you do not need to specify a default value, it is nil.

Class initializers and structs that set property values ​​are called designated. You can design an arbitrary number of designated initializers with a different set of parameters within the same object type. In this case, there must be at least one designated initializer that sets the values ​​of all properties (if they exist), and one of the designated initializers must be invoked when creating an instance. A designated initializer cannot call another designated initializer, that is, using the self.init () construct is prohibited.

Initializers inherit from superclass to subclass.

The only initializer that a designated initializer can call is a derived class initializer that calls the parent class’s initializer to set the values ​​of inherited properties. We talked about this in some detail when we studied inheritance.

The initializer can set the values ​​of constants.

Inside the initializer, you must set the values ​​of the properties of the class or structure so that by the end of its operation all properties have values ​​(optionals can correspond to nil).

Convenient initializers

In addition to the designated ones, there are convenience initializers in Swift. They are secondary and supportive. You can define a helper initializer to perform customizations and make sure to call one of the designated initializers. Convenient initializers are optional to implement on a type. Create them if it provides the most rational way to solve the problem at hand.

The syntax for declaring helper initializers is not too different from the syntax for those assigned.

SYNTAX

convenience init(параметры) {
    // тело инициализатора
}

A convenience initializer is declared with the convenience modifier followed by the init keyword. This type of initializer can also take input arguments and set values ​​for properties.

The body of the initializer must contain a call to one of the designated initializers.

Let’s go back to the hierarchy of the previously defined Quadruped, Dog and NoisyDog classes. Let’s rewrite the Dog class so that when installed, it allows arbitrary text to be output to the console. To do this, let’s create a helper initializer that takes as input a value for the inherited type property (Listing 27.1).

class Dog: Quadruped {
   override init() {
      super.init()
      self.type = "dog"
   }
   convenience init(text: String) {
      self.init()
      print(text)
   }
   func bark() {
      print("woof")
   }
   func printName() {
      print(self.name)
   }
}
var someDog = Dog(text: "Экземпляр класса Dog создан")

As a result, when creating a new instance of the Dog class, you will be prompted to choose one of two initializers: init () or init (text :). The convenience initializer calls the designated one and prints the text to the console.

A helper initializer can be called through another helper initializer.

Initializer inheritance

Initializer inheritance is different from inheriting normal superclass methods. There are two important rules to remember:

– If the subclass has its own designated initializer, then the parent class’s initializers are not inherited.
– If a subclass overrides all designated initializers of a superclass, then it inherits all of its auxiliary initializers as well.

Relationships between initializers

When it comes to relations between initializers, Swift follows these rules:

– The designated initializer of the subclass must invoke the designated initializer of the superclass.
– A convenience initializer must call a designated initializer of the same object type.
– The convenience initializer must ultimately call the designated initializer.

In fig. 27.1. all three rules are presented

image

Shown here is a superclass with one designated and two auxiliary initializers. One of the helper initializers calls the other, which in turn calls the designated one. Also depicted is a subclass with two assigned initializers and one auxiliary.

Calling any of the initializers shown should ultimately call the designated superclass initializer (top-left box).

Failing initializers

In some situations, it is necessary to define an object type, the creation of an instance of which may fail, caused by an incorrect set of external parameters, the absence of any external resource, or other circumstance. Failable initializers serve this purpose. They are capable of returning nil when attempting to create an instance. And this is their main purpose.

SYNTAX

init?(параметры) {
   // тело инициализатора
}

To create a failing initializer, use the init? (with a question mark), which indicates that the returned instance will be optional or not at all.

Return nil must be present in the body of the initializer.

Let’s look at an example implementation of a failing initializer. Let’s create a class that describes the “rectangle” entity. When creating an instance of this class, it is necessary to control the values ​​of the passed parameters (height and width) so that they are necessarily greater than zero. In this case, in case of incorrect parameter values, the program should not terminate with an error.

To solve this problem, we will use a failing initializer (Listing 27.2).

Listing 27.2

class Rectangle {
   var height: Int
   var weight: Int
   init?(height h: Int, weight w: Int) {
      self.height = h
      self.weight = w
      if !(h > 0 && w > 0) {
         return nil
     }
   }
}
var rectangle = Rectangle(height: 56, weight: -32) // возвращает nil

The initializer takes and checks the values ​​of two parameters. If at least one of them is less than or equal to zero, then nil is returned. Note that the initializer sets the values ​​of all stored properties before returning nil.

In classes, a failing initializer can return nil only after setting the values ​​of all stored properties. This limitation is absent for structures.

A designated initializer in a subclass can override a superclass’s failing initializer, and a failing initializer can invoke a designated initializer of the same class.

Remember that if you use a failing initializer, an optional is returned. Therefore, before working with the instance, you must retrieve the optional value.

You can use a failing initializer to select an appropriate enumeration member based on the values ​​of the input arguments. Consider the example from Listing 27.3. This example declares a TemperatureUnit enumeration that contains three members. A failing initializer is used to return an enumeration member corresponding to the passed parameter, or nil if the parameter value is invalid.

Listing 27.3

enum TemperatureUnit {
   case Kelvin, Celsius, Fahrenheit
   init?(symbol: Character) {
      switch symbol {
   case "K":
      self = .Kelvin
   case "C":
      self = .Celsius
   case "F":
      self = .Fahrenheit
   default:
      return nil
      }
   }
}
let fahrenheitUnit = TemperatureUnit(symbol: "F")

When an enumeration is instantiated, a value is passed as an input parameter to symbol. The corresponding enumeration member is returned based on the passed value.

Enumerations that have member values ​​have a built-in failing initializer init? (RawValue :). It can be used without being defined in code (Listing 27.4).

Listing 27.4

enum TemperatureUnit: Character {
   case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
fahrenheitUnit!.hashValue

Members of the TemperatureUnit enumeration are of type Character. In this case, you can call the built-in failing initializer, which will return an enum member that matches the passed value.

An alternative to init initializer? is the init operator! .. The only difference is that the second one returns an implicitly retrieved instance of the object type, since you do not need to additionally retrieve an optional value to work with it. This can still return nil.

»More details about the book can be found at website of the publishing house

Table of contents

Excerpt

For Habitants, a 25% discount on a coupon – Swift

Upon payment for the paper version of the book, an e-book is sent to the e-mail.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *