
Learning Swift from a C# Perspective
Comparing and Defining Structures and Classes #
1. Core Concepts #
- Concept Explanation:
In Swift, structures (
struct) and classes (class) are general-purpose building blocks of your code. Both can define properties to store values and define methods to provide functionality. Unlike Objective-C or C++, Swift does not require you to create separate interface (.h) and implementation (.m) files; you define them in a single file. Although their syntax is similar, Classes have additional capabilities: inheritance, runtime type casting, deinitializers, and reference counting. However, Apple officially recommends preferring Structs by default, unless you specifically need the features unique to classes or require reference semantics. - Key Syntax:
struct,class,Properties,Methods,Initializers - Official Note:
Traditionally, instances of a class are known as objects. However, Swift structures and classes are much closer in functionality than in other languages, and much of this chapter describes functionality that applies to instances of either a class or a structure type. Therefore, the more general term “instance” is used.
2. Example Analysis #
Source Code:
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}Logic Explanation:
This code defines a structure named Resolution to describe pixel resolution, and a class named VideoMode to describe video modes. Swift automatically infers the property types as Int based on the initial values (e.g., 0). The name property is defined as String? (Optional String), so it automatically receives a default value of nil.
3. C# Developer Perspective #
Concept Mapping:
This corresponds directly to struct and class definitions in C#.
C# Comparison Code:
struct Resolution {
public int Width;
public int Height;
// C# structs are usually recommended to be Immutable; this is just for comparing Swift syntax
}
class VideoMode {
public Resolution Resolution = new Resolution();
public bool Interlaced = false;
public double FrameRate = 0.0;
public string? Name; // C# 8.0+ Nullable Reference Types
}Key Differences Analysis:
- Syntax:
- Swift variable declarations use
var(mutable) orlet(constant), and do not require thepublickeyword to be accessible within the same module (default isinternal). - Swift property declarations perform type inference directly from the initial value, making the syntax more concise than C#.
- Swift variable declarations use
- Behavior:
- Swift Structs can implement Protocols (similar to C# Interfaces), have methods, Extensions, etc., possessing almost all capabilities of a Class except inheritance.
- In C#, Structs are typically used for lightweight data encapsulation. In Swift, Structs are First-Class Citizens; even
String,Array, andDictionaryin the standard library are Structs.
Structure and Class Instances & Accessing Properties #
1. Core Concepts #
- Concept Explanation:
Once types are defined, you need to create “instances” to use them. Swift uses initializer syntax to create instances; the simplest form is writing the type name followed by empty parentheses
(). Properties are accessed using dot syntax (.). - Key Syntax:
Instance,Dot Syntax,Initializer Syntax
2. Example Analysis #
Source Code:
let someResolution = Resolution()
let someVideoMode = VideoMode()
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0".
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is now 1280".Logic Explanation:
Here, instances of Resolution and VideoMode are created, and their properties are accessed. Notably, even deep properties (like someVideoMode.resolution.width) can be read and assigned directly using dot syntax.
3. C# Developer Perspective #
Concept Mapping: This is almost identical to object creation and property access in C#.
C# Comparison Code:
var someResolution = new Resolution();
var someVideoMode = new VideoMode();
Console.WriteLine($"The width of someResolution is {someResolution.Width}");
someVideoMode.Resolution.Width = 1280;Key Differences Analysis:
- Syntax:
- Swift instance creation does not require the
newkeyword. This is the most common habit C# developers need to break. - Swift string interpolation uses
\(variable), whereas C# uses$"{variable}".
- Swift instance creation does not require the
Memberwise Initializers for Structure Types #
1. Core Concepts #
- Concept Explanation: Swift Structs have a very convenient feature: if you do not define a custom initializer, the compiler automatically generates a “Memberwise Initializer” for you, allowing you to initialize member properties directly. Classes do not have this feature.
- Key Syntax:
Memberwise Initializer
2. Example Analysis #
Source Code:
let vga = Resolution(width: 640, height: 480)Logic Explanation:
Since Resolution is a Struct, it automatically gains an initializer containing width and height parameters.
3. C# Developer Perspective #
Concept Mapping:
Standard C# struct (prior to C# 10) did not have this automatic behavior. C# 12 introduced Primary Constructors, and record struct can achieve similar results, but standard C# class or struct types usually require manually writing constructors or using Object Initializer syntax.
C# Comparison Code:
// C# Object Initializer syntax
var vga = new Resolution { Width = 640, Height = 480 };
// Or if a constructor is defined
// var vga = new Resolution(640, 480);Key Differences Analysis:
- Syntax: Swift’s memberwise initializer is in the form of function parameters
(width: 640), whereas C# object initializers use curly braces for property assignment{ Width = 640 }. - Behavior: Swift’s auto-generated initializer enforces parameter passing (unless properties have default values). C#’s Object Initializer (
{ }) simply sets properties after object creation, which is semantically different. Swift Classes do not automatically get this initializer; you must manually defineinit.
Structures and Enumerations Are Value Types #
1. Core Concepts #
- Concept Explanation:
A Value Type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function. In Swift, all
structandenumtypes are Value Types. This includesInt,Double,Bool,String,Array, andDictionaryin the Swift Standard Library. - Key Syntax:
Value Type,Copy - Official Note:
Collections defined by the Swift standard library like arrays, dictionaries, and strings use an optimization to reduce the performance cost of copying. Instead of making a copy immediately, these collections share the memory where the elements are stored. The actual copy is performed only when one of the copies is modified (Copy-on-Write).
2. Example Analysis #
Source Code:
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide".
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide".Logic Explanation:
When hd is assigned to cinema, a copy occurs. Therefore, modifying the width of cinema does not affect the original hd at all. They are two independent instances in memory.
3. C# Developer Perspective #
Concept Mapping:
C# struct is also a Value Type, and behaves identically in this regard.
Key Differences Analysis:
- Behavior (Crucial):
- String Differences: C#
stringis a Reference Type (though its immutability makes it behave somewhat like a value type), but in Swift,Stringis a Struct (Value Type). This means Swift string passing involves copying behavior (logically), representing a significant conceptual shift for C# developers. - Collection Differences: C#
List<T>orDictionary<TKey, TValue>are Classes (Reference Types). If you assign a List to another variable, modifying one affects the other. In Swift,ArrayandDictionaryare Structs; assignment creates a copy, and modifications are independent. This is the most common pitfall for C# developers moving to Swift.
- String Differences: C#
Classes Are Reference Types #
1. Core Concepts #
- Concept Explanation:
Reference Types are not copied when assigned or passed; instead, a reference to the same existing instance is used. Multiple variables can point to the same instance in memory. Swift
classis a Reference Type. - Key Syntax:
Reference Type,Shared Instance
2. Example Analysis #
Source Code:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0".Logic Explanation:
tenEighty and alsoTenEighty refer to the same VideoMode instance. Therefore, modifying frameRate via alsoTenEighty also changes the value seen by tenEighty.
3. C# Developer Perspective #
Concept Mapping:
This corresponds exactly to C# class behavior.
Key Differences Analysis:
- Syntax:
- Note that the example uses
let tenEighty = VideoMode()(constant). In Swift, this means thetenEightypointer cannot change (it cannot point to a different object), but the content of the object it points to can be changed. This is similar to areadonlyfield holding a Reference Type in C#. - If
VideoModewere a Struct, declaring it withletwould prevent modification of any of its properties (because a Struct treats its content as a single value).
- Note that the example uses
Identity Operators #
1. Core Concepts #
- Concept Explanation:
Because classes are reference types, it is sometimes necessary to determine if two variables “refer to exactly the same instance in memory.” Swift provides
===(Identical to) and!==(Not identical to) for this purpose. - Key Syntax:
===,!==
2. Example Analysis #
Source Code:
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}Logic Explanation:
Here, === is used to check if two variables refer to the same VideoMode instance. Note that this is different from == (Equal to); == is typically used to compare if “values” are equal (requires conforming to the Equatable protocol).
3. C# Developer Perspective #
Concept Mapping:
This is equivalent to Object.ReferenceEquals(a, b) in C#, or the default behavior of the == operator on reference types when not overloaded.
C# Comparison Code:
if (Object.ReferenceEquals(tenEighty, alsoTenEighty)) {
// ...
}
// Or for standard classes
if (tenEighty == alsoTenEighty) { }Key Differences Analysis:
- Syntax: Swift strictly distinguishes between “Reference Identity (
===)” and “Value Equality (==)”. C#’s==compares references by default for Reference Types, but compares values forstringor types that overload operators, which can be confusing. Swift’s design is more explicit.