Swift ( Enums VS Structures VS Classes)
Coming from an objective c background, the difference between components like enums, classes, and structs was quite obvious for me: An Enum is a set of named values, Struct is structured data type, and of course Class allows us to create objects with all POO related stuff.
When i first started learning Swift, it was a little confusing. Since sometime they may look similar. And Structs might be found in swift where only classes were used in some other languages.
- For instance : Enums and Structs may also have methods or constructors.
Personally I needed some time to get familiar with the extended features we have with structs and enumerations in swift.
So in order to know where to use each one. it’s important to have a clear understanding of what makes one different from another. So let’s try to go over them one by one.
Reference types & Value types
The key difference between classes from one side, and enumerations and structures from another. Is that Classes are reference types, while enumerations and structures are value types .
Which means when you assign a class type object to an other. They become
pointing on the same instance. Hence when one is modified, the modification is applied to the other :
class Cat { var name:String init(name:String) { self.name = name }}var cat1 = Cat(name: "Kitty")var cat2 = cat1cat1.name = "Oscar"
// Both cats are the sameprint("cat1 name : \(cat1.name), cat2 name : \(cat2.name)")
// cat1 name : Oscar, cat2 name : Oscar
while for structures and enumerations a new copy is created on every assignment :
struct Cat {var name:String}var cat1 = Cat(name: "Kitty")var cat2 = cat1cat1.name = "Oscar"print("cat1 name : \(cat1.name), cat2 name : \(cat2.name)")
//cat1 name : Oscar, cat2 name : Kitty
Mutability
The fact that structs and enums are values types, has some other side effects apart from assignment.
When a Structs is created as a constant (using let) , the whole instance is immutable. Which means we are not allowed to modify its properties :
struct Cat { var name:String}let cat1 = Cat(name: "Kitty")cat1.name = "Oscar"// error: cannot assign to property
But for classes. Even when its a constant, only the reference is immutable. while the properties could be modified without issues :
class Cat { var name:String?}let cat1 = Cat()cat1.name = "Oscar"// Working fine
Even when declared as a variable (var), a struct cannot modify itself. and to do so, we need to use mutating keyword. which is not available for classes :
struct Cat { private var vaccinated:Bool init() { self.init() } // Will not work without mutating keyword mutating func vaccinate() { self.vaccinated = true }}var cat1 = Cat()cat1.vaccinate()
Deinitializer
While having init method for both values and reference types. deinit method does not exist for value types. knowing that they are not concerned by reference counting :
struct Cat { var name:String deinit { }}
// Compiler Error : Deinitializers may only be declared within a class
Generated init
An option possible only with structs. “Generated init methods” that are based on properties :
struct Cat {var name:Stringvar age:Int}let cat1 = Cat(name: "Lucy", age: 3)
Inheritance
Also note that only classes supports inheritance :
struct Pet { var name:String}struct Cat : Pet {}
// ERROR : Inheritance from non-protocol type 'Pet'
Stored properties
Unlike Classes and Structs, an enum cannot contain a stored property :
enum Pet {
var name:String
// error: enums must not contain stored properties
}
Conclusion
Finally we can say that structs are used where we want to represent a data structure. Mainly models. While classes are used in most of other cases.
You can note also that structs are considered to be thread-safe. Due to their value type nature.