SoFunction
Updated on 2025-04-11

Detailed explanation of Swift tutorials and structures

Classes and structures are code blocks that programmers often use in code. In classes and structures, you can define related properties and methods like defining constants, variables and functions to achieve various functions.

Unlike other programming languages, Swift does not need to create interfaces or implement files separately to use classes or structures. Classes or structures in Swift can be directly defined in a single file. Once the definition is completed, they can be directly used by other codes.

Note: An instance of a class is generally regarded as an object, but in Swift, classes and structures are more like functional methods, and in subsequent chapters, they talk more about the functionality of classes and structures.

1. Similarities and similarities between classes and structures

Classes and structures have some similarities, and they can all be:

Define some attributes that can be assigned;

Define a functional method

Define subscripts, use subscript slogan

Define the initialization method to set the initial state

Scalability in the original implementation method

Provide basic functions of a specific category according to the protocol

More content can be read: properties, methods, subscripts, initialization, extensions and protocols, etc.

There are some features that are not available in the class:

Class inheritance

Real-time type conversion to class instances

Deconstruct an instance of a class to free up space

Reference count, a class instance can have multiple references

More content can be read: Inheritance, Type Conversion, Initialization of Automatic Reference Count

Note: The structure is copied every time it is passed in the code, so don't use reference counting

Definition syntax

Classes and structures have similar definition syntax. Use class keywords to define a class, and struct keywords to define a structure. Each definition is contained by a pair of braces:

Copy the codeThe code is as follows:
 
class SomeClass {
// class definition goes here
}
struct SomeStructure {
// structure definition goes here
}

Note: When defining classes and structures, the UpperCamelCase nomenclature is generally used to define the names of classes and structures, such as SomeClass and SomeStructure, which also complies with other Swift types of standards. When naming attributes and methods, lowerCamelCase is usually named, such as frameRate and incrementCount.
Here is an example of a structure and a class definition:

Copy the codeThe code is as follows:
 
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = falsevar
frameRate = 0.0
var name: String?
}

The above example first defines a structure called Resolution to describe the resolution of a pixel display. It has two properties called width and height. These two properties are defined as Int type by default and are initialized to 0.

Then a class called VideoMode is defined to display the video. This class has four properties, the first property resolution itself is a structure, and then the other two properties. The last property uses the optional string type String?, which means that this property can exist or does not exist as nil.

Examples of classes and structures

The above two definitions only define the overall style of the structure Resolution and class VideoMode. They themselves are not a specific resolution or display method. At this time, the structure and class need to be instantiated.

The syntax of instantiation is similar:

Copy the codeThe code is as follows:

let someResolution = Resolution()
let someVideoMode = VideoMode()

Both classes and structures use instance syntax to complete instantiation. The simplest example syntax is to complete it with two brackets (). In this case, the properties in the instance defined will complete the default initialization. For more content, please refer to the initialization chapter.

Access properties

Use the . syntax to easily access the properties of an instance. In . syntax, add (.) after the instance name, and no space is needed:

Copy the codeThe code is as follows:

println("The width of someResolution is \()")
// prints "The width of someResolution is 0"

In this example, the width attribute representing someResolution returns its initial value 0

You can also use the .grammar to continuously obtain properties of properties, such as the width attribute of the resolution property in VideoMode

Copy the codeThe code is as follows:
 
println("The width of someVideoMode is \()")
// prints "The width of someVideoMode is 0"

Using this method not only allows you to access, but also assign values:

Copy the codeThe code is as follows:
 
= 1280
println("The width of someVideoMode is now \()")
// prints "The width of someVideoMode is now 1280"

Note: Unlike Objective-C, Swift can directly set a sub-property of a structural property, just like in the above example.

Member initialization method of structure type

Each structure has a member initialization method, and the initial value of each attribute can be specified by using the attribute name during initialization:

Copy the codeThe code is as follows:
 
let vga = Resolution(width: 640, height: 480)

However, unlike the structure, class instances cannot use member initialization methods. There is a special introduction in the initialization chapter.

2. Structure and enumeration types are numeric types

A numerical type means that when it is assigned to a constant or variable, or passed as a parameter to a function, a new numerical value is copied intact, rather than just changing the reference object.

In fact, after reading this, you have seen numeric types in the previous chapters. All the basic types in Swift - integers, floating point, booleans, strings, arrays and dictionaries are numeric types. They are also implemented by structures.

All structures and enum types in Swift are numeric types. This means that every structure and enum you instantiate, all the properties it contains, will be completely copied when passed in the code.

The following example illustrates this feature:

Copy the codeThe code is as follows:
 
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd

Declare a constant hd, which is an instantiation of Resolution, with a width of 1920 and a height of 1080, and then declares a variable cinema, which is the same as hd. This time shows that cinema and hd are two instances, although their widths are both 1920 and their heights are both 1080.

If the width of cinema is changed to 2048, the width of hd will not change, it is still 1920

Copy the codeThe code is as follows:
 
= 2048
println("cinema is now \() pixels wide")
// prints "cinema is now 2048 pixels wide"
println("hd is still \() pixels wide")
// prints "hd is still 1920 pixels wide"

This shows that when hd is assigned to cinema, a brand new Resolution structure is completely copied to cinema, so when the cinema attribute is modified, the hd attribute will not change.

The following example demonstrates the enum type:

Copy the codeThe code is as follows:

enum CompassPoint {
case North, South, East, West
}
var currentDirection =
let rememberedDirection = currentDirection
currentDirection = .East
if rememberedDirection == .West {
println("The remembered direction is still .West")
}
// prints "The remembered direction is still .West"

Despite several assignments, rememberedDirection still remains unchanged, because during each assignment, the numerical type is completely copied.

3. Class is a reference type

A reference type different from a numeric type will not copy the entire instance. When it is assigned to another constant or variable, it will create a reference related to the existing instance to represent it.

Here is a referenced example, VideoMode is defined as a class:

Copy the codeThe code is as follows:
 
let tenEighty = VideoMode()
= hd
= true
= "1080i"
= 25.0

The four attributes of tenEighty are initialized in this instance, and then the tenEighty is assigned to another constant called alsoTenEighty, and the frameRate of alsoTenEighty is modified.

Copy the codeThe code is as follows:

let alsoTenEighty = tenEighty
= 30.0

Since the class is a reference type, tenEighty and alsoTenEighty are actually the same instance, just using different names. We can prove this problem by checking frameRate:

Copy the codeThe code is as follows:
 
println("The frameRate property of tenEighty is now \()")
// prints "The frameRate property of tenEighty is now 30.0"

Note that tenEighty and alsoTenEighty are defined as constants, not variables. But we can still change their attribute values, because they themselves have not changed. They do not save this VideoMode instance, they simply refer to a VideoMode instance, and what we modify is the attributes in the instance they refer to.

Feature Operation

Because the class is a reference type, there may be multiple constants or variables that only want instances of the same class (this is not true for numerical types structures and enumerations).

You can use the following two operations to determine whether the two constants or variables refer to instances of the same class:

Same instance (===)

Different instances (!==)

Use these actions to check:

Copy the codeThe code is as follows:
 
if tenEighty === alsoTenEighty {
println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
// prints "tenEighty and alsoTenEighty refer to the same Resolution instance."

Note that the same instance determines that three consecutive equal signs are used, which are different from equality (two equal signs).

The same instance represents an instance of the same class that two variables or constants refer to.

Equality means the numerical equality of two instances, or the same.

When you define a class, you need to explain what happens when two classes are equal and when two classes are not equal. More content can be obtained from the chapter on equal operations.

pointer

If you have C, C++ or Objective-C programming experience, you must know to use pointers to reference a memory address in these languages. Constants or variables that refer to an instance in Swift are similar to pointers in C, but are not pointers directly to memory addresses, and you do not need to use * tokens to indicate that you are defining a reference. References and other variables in Swift are defined in the same way as those in Swift.

4. How to choose to use a class or a structure

In the code, you can select a class or structure to implement the code block you need and complete the corresponding functions. But the structure instance passes the value, while the class instance passes the reference. Then for different tasks, different instances should be selected to consider the different requirements of data structures and functions.

Generally speaking, when one or more of the following conditions are met, you should choose to create a structure:

The structure is mainly used to encapsulate some simple data values

When assigning or passing, it is more desirable that these encapsulated data be assigned instead of being referenced in the past

All properties stored by structures are numerical types themselves

The structure does not need to be inherited by another type or completes other behaviors.

Some better examples of using structures:

A geometric dimension, which may include width, height, or other attributes, each attribute of type Double

The correspondence of a sequence may include the start and length attributes, each attribute is of type Int

A point in the 3D coordinate system, including x, y and z coordinates, is of type Double

In other cases, classes would be a better choice. In other words, under normal circumstances, some custom data structures are generally defined as classes.

5. Assignment and copy operations of collection types

In Swift, array Array and dictionary Dictionary are implemented using structures, but arrays are somewhat different from dictionaries and other structures when assigning values ​​or passing them as parameters to functions.

And these operations of arrays and dictionaries are different from NSArray and NSDictionary in Foundation, and they are implemented using classes.

Note: The following sections will introduce the copying operations of arrays, dictionaries, strings, etc. These replication operations seem to have already happened, but Swift will only copy in full when it really needs to be replicated, thus achieving optimal performance.

Dictionary assignment and copy operations

Each time a dictionary Dictionary type is assigned to a constant or variable, or passed as a parameter to a function, the dictionary will be copied only when the assignment or function is called. This process is described in the above subsection: Structures and Enumerations are numeric types.

If the key values ​​in the dictionary are numeric types (structures or enumerations), they will be copied at the same time when assigned. On the contrary, if it is a reference type (class or function), the reference itself will be copied, not the class instance or function itself. This copying method and structure of the dictionary are the same.

The following example demonstrates a dictionary called ages, which stores some correspondence between person's name and age. When assigned to copyAges, the values ​​inside are completely copied at the same time. When the copied value is changed, the original value will not change, as shown in the following example:

Copy the codeThe code is as follows:
 
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages

The keys of this dictionary are of String type, and the value is of Int type, and they are all numeric types, so they will be completely copied when assigned.

Copy the codeThe code is as follows:

copiedAges["Peter"] = 24
println(ages["Peter"])
// prints "23"

Assignment and copying operations of arrays

Compared with the dictionary Dictionary type, the assignment and copying operations of array Array are more complicated. The Array type is similar to that in C language, and the value of the array will be completely copied only when needed.

If an array is assigned to a constant or variable, or passed as a parameter to a function, copying does not happen when the assignment and function calls. These two arrays will share a sequence of elements, and if you modify one, the other will also change.

For arrays, copying will only happen if you have performed an operation that might modify the array length. Including splicing, adding or removing elements, etc. When copying actually occurs, it will be like the assignment and copying operations of a dictionary.

The following example demonstrates the assignment operation of an array:

Copy the codeThe code is as follows:
 
var a = [1, 2, 3]
var b = a
var c = a

Array a is assigned to b and c, and then outputting the same subscript will find:

Copy the codeThe code is as follows:
 
println(a[0])
// 1
println(b[0])
// 1
println(c[0])
// 1

If you change a value in a, you will find that the values ​​in b and c will also change, because the assignment operation does not change the length of the array:

Copy the codeThe code is as follows:
 
a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42

However, if a new element is added to a, the length of the array is changed, and the actual copy operation will occur. If the value of the element in a is changed, the elements in b and c will not change:

Copy the codeThe code is as follows:

(4)
a[0] = 777
println(a[0])
// 777
println(b[0])
// 42
println(c[0])
// 42

Setting an array is unique

It would be best if you can set it to unique before modifying the array. We can copy the array by using the unshare method and become a unique entity.

If multiple variables refer to the same array, you can use the unshare method to complete a "independent" one

Copy the codeThe code is as follows:

()

If the value of b is modified at this time, the value of c will not be affected again

Copy the codeThe code is as follows:
 
b[0] = -105
println(a[0])
// 777
println(b[0])
// -105
println(c[0])
// 42

Checking two arrays to share the same element

Use the instance equality operator to determine whether two arrays share elements (=== and !===)

The following example demonstrates whether elements are shared:

Copy the codeThe code is as follows:
 
if b === c {
println("b and c still share the same array elements.")
} else {
println("b and c now refer to two independent sets of array elements.")
}
// prints "b and c now refer to two independent sets of array elements."

You can also use this operation to determine whether the two subarrays have common elements:

Copy the codeThe code is as follows:
 
if b[0...1] === b[0...1] {
println("These two subarrays share the same elements.")
} else {
println("These two subarrays do not share the same elements.")
}
// prints "These two subarrays share the same elements."

Forced array copy

Forced copy is completed by calling the copy method of the array. This method will completely copy an array into the new array.

In the following example, this array called names will be completely copied into copiedNames.

Copy the codeThe code is as follows:
 
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = ()

By changing the value of copyNames, it can be verified that the array has been completely copied and will not affect the previous array:

Copy the codeThe code is as follows:
 
copiedNames[0] = "Mo"
println(names[0])
// prints "Mohsen"

Note: If you are not sure if the array you need is independent, just use unshare. The copy method will be copied in full regardless of whether it is currently independent or not, even if the array is already unshare.