Why Choose Struct Over Class?
Asked Answered
N

17

563

Playing around with Swift, coming from a Java background, why would you want to choose a Struct instead of a Class? Seems like they are the same thing, with a Struct offering less functionality. Why choose it then?

Neighboring answered 15/6, 2014 at 18:33 Comment(8)
Structures are always copied when they are passed around in your code, and do not use reference counting. source: developer.apple.com/library/prerelease/ios/documentation/swift/…Gybe
I would say that structs are more appropriated to hold data, not logic. To speak in Java terms, imagine structs as "Value Objects".Unionist
I'm amazed in this whole conversation there is no direct mention of copy-on-write a.k.a. lazy copy. Any concerns about struct copy performance are mostly moot on account of this design.Sapphirine
Choosing a struct over a class is not a matter of opinion. There are specific reasons to choose one or the other.Sapphirine
I highly recommend to see Why Array is not threadSafe. It's related because Arrays & Structs are both value types. All answers here mention that with structs/arrays/value types will never have a thread Safety issue, but there is a corner case in which you will.Calcareous
Apple now (as of 2019) has an article that directly addresses this question Choosing Between Structures and Classes.Intended
@DavidJames The Swift Programming Language: Structures and Classes: Structures and Enumerations Are Value Types says: "Collections defined by the standard library like arrays, dictionaries, and strings" (not all structs) use the copy-on-write technique. See Does swift copy on write for all structs?Saguaro
Swift aside, I'm slowly coming to the conclusion that using Java as a primary teaching language might be more of a problem than I first thought in the late 90's. Forget pointer (arithmetic), there seems to be a complete lack of understanding of what a compound value type is, and why it's important. C# made sure to include it, C and C++ obviously have it, but it's absent from both Java and its JVM until the Valhalla initiative takes hold.Mogul
T
625

According to the very popular WWDC 2015 talk Protocol Oriented Programming in Swift (video, transcript), Swift provides a number of features that make structs better than classes in many circumstances.

Structs are preferable if they are relatively small and copiable because copying is way safer than having multiple references to the same instance as happens with classes. This is especially important when passing around a variable to many classes and/or in a multithreaded environment. If you can always send a copy of your variable to other places, you never have to worry about that other place changing the value of your variable underneath you.

With Structs, there is much less need to worry about memory leaks or multiple threads racing to access/modify a single instance of a variable. (For the more technically minded, the exception to that is when capturing a struct inside a closure because then it is actually capturing a reference to the instance unless you explicitly mark it to be copied).

Classes can also become bloated because a class can only inherit from a single superclass. That encourages us to create huge superclasses that encompass many different abilities that are only loosely related. Using protocols, especially with protocol extensions where you can provide implementations to protocols, allows you to eliminate the need for classes to achieve this sort of behavior.

The talk lays out these scenarios where classes are preferred:

  • Copying or comparing instances doesn't make sense (e.g., Window)
  • Instance lifetime is tied to external effects (e.g., TemporaryFile)
  • Instances are just "sinks"--write-only conduits to external state (e.g., CGContext)

It implies that structs should be the default and classes should be a fallback.

On the other hand, The Swift Programming Language documentation is somewhat contradictory:

Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure.

As a general guideline, consider creating a structure when one or more of these conditions apply:

  • The structure’s primary purpose is to encapsulate a few relatively simple data values.
  • It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
  • Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
  • The structure does not need to inherit properties or behavior from another existing type.

Examples of good candidates for structures include:

  • The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double.
  • A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int.
  • A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double.

In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures.

Here it is claiming that we should default to using classes and use structures only in specific circumstances. Ultimately, you need to understand the real world implication of value types vs. reference types and then you can make an informed decision about when to use structs or classes. Also, keep in mind that these concepts are always evolving and The Swift Programming Language documentation was written before the Protocol Oriented Programming talk was given.

Teenyweeny answered 15/6, 2014 at 18:37 Comment(22)
@ElgsQianChen the whole point of this writeup is that struct should be chosen by default and class should only be used when necessary. Structs are much safer and bug free, especially in a multithreaded environment. Yes, you can always use a class in place of a struct, but structs are preferable.Teenyweeny
@Teenyweeny That seems to be the exact opposite of what it is saying. It was saying that a class should be the default that you use, not a structure In practice, this means that most custom data constructs should be classes, not structures. Can you explain to me how, after reading that, you get that most data sets should be structures and not classes? They gave a specific set of rules when something should be a struct and pretty much said "all other scenarios a class is better."Articulate
@Matt, that's true. The way I choose to look at this is that we have specific places a Struct can be used while a Class can be used anywhere including in place of structs. That means to me that classes are a fallback for when structs will not cut it.Teenyweeny
Last line should say, "My personal advice is the opposite of the documentation:"... and then it's a great answer!Billowy
Immutability is a big "thing" amongst code nerds: programmers.stackexchange.com/questions/151733/… It's a deep debate, but apparently it does help avoid bugs.Billowy
I hope Apple reads this post. Thanks for illuminating this dichotomy @TeenyweenyEdington
@Teenyweeny can you please see this stackoverflow.com/questions/33525160/…Tomikotomkiel
Swift 2.2 book still says use classes in most situations.Sapphirine
Well according to this, they seem to imply to use structs :/ youtube.com/watch?v=av4i3x-aZbMPuebla
Struct over Class is definitely reduce the complexity. But what is the implication on memory usage when structs becomes the default choice. When things get copied everywhere instead of reference it should increase the memory usage by the app. Shouldn't it?Goldina
With Structs there is no need to worry about memory leaks or multiple threads racing to access/modify a single instance of a variable. <-- I think for copies there is no issue, but for single instance (uncopied & also accessed from multiple threads like read-write) you will have race conditions. See Rob's answer here and see here about the thread safe of array which similar to structs is a value typeCalcareous
@Honey It is true that it is possible to actually copy a reference to a value type in a closure which makes it not thread safe. You can protect this by explicitly indicating captured types should be copied in a capture list and this will make them true value types again and therefore thread safe.Teenyweeny
I'm not talking about that. That statment you made about their thread safety is confusing and may not be correct. Did you see links in my comment?Calcareous
@Honey that is exactly what I am referring too. I will also edit my answer to hopefully make it a bit more clear. Yes it is possible to still have a race condition with a (struct) value type if you capture it in a closure. that is because of what I just said: closures can capture even a value type as a reference.Teenyweeny
“unless you explicity mark it to be copied” - how can I do this? I’ve done many searches and there’s nothing in the docs, when you say “mark” here what do you mean? Just a copy() call?Damar
"Classes can also become bloated because a class can only inherit from a single superclass." - well, class can conform to protocols as well so the argument seems a bit weird. A better way to frame it may be "Using class inheritance can also become bloated...".Gosser
The Swift language reference is NOT contradictory, but maybe it could be written more clearly. Structures are more like dumb data objects. If you want to build any thing the OOP way, you won't have a bunch of data just lying around with lots of global functions operating on them, but instances of classes that have both data and routines. In that sense, unless you're building something like a JSON wrapper, most data types you define will be classes. If this is not the case for your project, I'm not sure if it is object-oriented.Weary
@BridgeTheGap Structures in Swift are in no way dumb objects. They can do everything a class can do except for inheritance. You certainly don't need inheritance to do OOP, especially when you can use protocols. The most important difference is how they are represented in memory (as plain data or a reference).Teenyweeny
@Teenyweeny Yes, the most important difference is where they are in memory, but why are they placed that way? Being able to do everything a class can do doesn't mean they should be used the same way. Also, Apple certainly seems to be replacing data classes with structures--URLRequest, URL, String, Array, Dictionary, etc--whereas most other building blocks are left alone. How often do you see structures sending messages to each other or other classes? I never said structures are dumb objects, but they certainly are close to one.Weary
It looks like Apple's advice has evolved as per your conclusion. The Swift Programming Language documentation now says 'As a general guideline, prefer structures because they’re easier to reason about, and use classes when they’re appropriate or necessary.'Intended
Also, in a recent (Jan 2019 or thereabouts?) article, Choosing Between Structures and Classes, they advise you to 'Use structures by default' but to 'Use classes when you need to control the identity of the data you're modeling'.Intended
It is worth noting that if a Struct contains a data member which is a Class, then a "copy" of that struct will have a reference to the original struct's (class) data member. A change in the object that is encapsulated within the struct will affect other copies of that struct.Dullish
P
179

This answer was originally about difference in performance between struct and class. Unfortunately there are too much controversy around the method I used for measuring. I left it below, but please don't read too much into it. I think after all these years, it has become clear in Swift community that struct (along with enum) is always preferred due to its simplicity and safety.

If performance is important to your app, do measure it yourself. I still think most of the time struct performance is superior, but the best answer is just as someone said in the comments: it depends.

=== OLD ANSWER ===

Since struct instances are allocated on stack, and class instances are allocated on heap, structs can sometimes be drastically faster.

However, you should always measure it yourself and decide based on your unique use case.

Consider the following example, which demonstrates 2 strategies of wrapping Int data type using struct and class. I am using 10 repeated values are to better reflect real world, where you have multiple fields.

class Int10Class {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

struct Int10Struct {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
    return IntClass(x.value + y.value)
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
    return IntStruct(x.value + y.value)
}

Performance is measured using

// Measure Int10Class
measure("class (10 fields)") {
    var x = Int10Class(0)
    for _ in 1...10000000 {
        x = x + Int10Class(1)
    }
}

// Measure Int10Struct
measure("struct (10 fields)") {
    var y = Int10Struct(0)
    for _ in 1...10000000 {
        y = y + Int10Struct(1)
    }
}

func measure(name: String, @noescape block: () -> ()) {
    let t0 = CACurrentMediaTime()
    
    block()
    
    let dt = CACurrentMediaTime() - t0
    print("\(name) -> \(dt)")
}

Code can be found at https://github.com/knguyen2708/StructVsClassPerformance

UPDATE (27 Mar 2018):

As of Swift 4.0, Xcode 9.2, running Release build on iPhone 6S, iOS 11.2.6, Swift Compiler setting is -O -whole-module-optimization:

  • class version took 2.06 seconds
  • struct version took 4.17e-08 seconds (50,000,000 times faster)

(I no longer average multiple runs, as variances are very small, under 5%)

Note: the difference is a lot less dramatic without whole module optimization. I'd be glad if someone can point out what the flag actually does.


UPDATE (7 May 2016):

As of Swift 2.2.1, Xcode 7.3, running Release build on iPhone 6S, iOS 9.3.1, averaged over 5 runs, Swift Compiler setting is -O -whole-module-optimization:

  • class version took 2.159942142s
  • struct version took 5.83E-08s (37,000,000 times faster)

Note: as someone mentioned that in real-world scenarios, there will be likely more than 1 field in a struct, I have added tests for structs/classes with 10 fields instead of 1. Surprisingly, results don't vary much.


ORIGINAL RESULTS (1 June 2014):

(Ran on struct/class with 1 field, not 10)

As of Swift 1.2, Xcode 6.3.2, running Release build on iPhone 5S, iOS 8.3, averaged over 5 runs

  • class version took 9.788332333s
  • struct version took 0.010532942s (900 times faster)

OLD RESULTS (from unknown time)

(Ran on struct/class with 1 field, not 10)

With release build on my MacBook Pro:

  • The class version took 1.10082 sec
  • The struct version took 0.02324 sec (50 times faster)
Polyvalent answered 16/6, 2014 at 12:22 Comment(16)
True, but it seems that copying a bunch of structs around would be slower than copying a reference to a single object. In other words it's faster to copy a single pointer around than to copy an arbitrarily large block of memory.Meany
In most cases you are not just copying a reference, but object's reference counter should be incremented/decremented as well and it can affect performance.Faris
-1 This test is not a good example because there is only a single var on the struct. Note that if you add several values and an object or two, the struct version gets comparable to the class version. The more vars you add, the slower the struct version gets.Camboose
@Camboose got your point, but an example is "good" or not depends on specific situation. This code was extracted from my own app, so it is a valid use case, and using structs did massively improves performance for my app. It's just probably not a common use case (well, the common use case is, for most apps, no one cares about how fast data can be passed around, since the bottleneck happens somewhere else, e.g. network connections, anyway, optimization is not that critical when you have GHz devices with GBs or RAM).Polyvalent
@KhanhNguyen thanks for the benchmark and +1 as a compensation. This is a decisive example for some use cases e.g. rendering lots of objects (again is some context).Elielia
As far as I understand copying in swift is optimized to happen at WRITE time. Which means that there is no physical memory copy made unless the new copy is about to be altered.Muscle
The comment by @Muscle is the key to the performance of Swift structs. More info in this tutorial: raywenderlich.com/112029/reference-value-types-in-swift-part-2Adamantine
If structs are kept on the stack, is there no risk of stack overflow? I mean, how much memory does a stack normally have? Think of millions of struct records an app can have.Pounds
@Pounds Hmmm very interesting question. I don't have the answer thought. On a side note, you can only get that many instances with an array of structs, and how Swift implements Array itself as a struct is a huge mystery to me.Polyvalent
This answer is showing an extremely trivial example, to the point of being unrealistic and therefore incorrect for many instances. A better answer would be "it depends."Edging
Add some reference type vars to your struct and see how perfomance will degrade. It can be worst than class because of reference counting overhead. Must see: developer.apple.com/videos/play/wwdc2016/416Peppy
Added GitHub fork to Khanh performance tests that runs simple test on "static func" vs "class func" using Swift 4.0 on Xcode 9 beta. Tests show that simple struct static func is faster on Simulator but has exactly the same performance on iPhone 7 running iOS 10.3: github.com/protyagov/StructVsClassPerformance – Alex Protyagov 4 hours agoHendiadys
The 2016 results look flawed. The A9 in an iPhone 6S runs at 1.8 GHz, which means a clock cycle takes ~5.6E-10 seconds. Your benchmark took 5.83E-08s, in other words: about 100 clock cycles. That would mean your CPU did 100,000 add operations per cycle. My guess is that either the compiler removed the entire block because it figured that the result is never used or it figured that you don't use any of the intermediate results and just replaced the end result with a static one calculated at compile time. Either way you probably just measured the measurement overhead itself.Vaulting
That 5.83E-08s number looks too good to be true. I think the compiler may be smart enough and just collapse all your operations in struct test case. This is known as “constant folding”. Try generate object file with the same optimization flag and inspect pseudo code with Hopper Disassembler and see what’s the real code after optimization it is testing on.Gosser
This test is questionable, apparently as @Gosser said, the code related to struct will be optimized, which will not be executed. You can add print(y.value) to disable this optimization, and the real result is struct is around 300 times faster than class.Emden
Or can we try testing again with Swift Compiler setting -Onone (compile with no optimization) instead -O (compile with optimization)?Gosser
G
65

Similarities between structs and classes.

I created gist for this with simple examples. https://github.com/objc-swift/swift-classes-vs-structures

And differences

1. Inheritance.

structures can't inherit in swift. If you want

class Vehicle{
}

class Car : Vehicle{
}

Go for an class.

2. Pass By

Swift structures pass by value and class instances pass by reference.

Contextual Differences

Struct constant and variables

Example (Used at WWDC 2014)

struct Point{
 
   var x = 0.0;
   var y = 0.0;

} 

Defines a struct called Point.

var point = Point(x:0.0,y:2.0)

Now if I try to change the x. Its a valid expression.

point.x = 5

But if I defined a point as constant.

let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.

In this case entire point is immutable constant.

If I used a class Point instead this is a valid expression. Because in a class immutable constant is the reference to the class itself not its instance variables (Unless those variables defined as constants)

Goldina answered 4/3, 2015 at 0:3 Comment(3)
You can inherit structs in Swift gist.github.com/AliSoftware/9e4946c8b6038572d678Pledgee
The above gist is about how we can achieve inheritance flavors for struct. You will see syntax like. A: B. It is struct called A implements protocol called B. Apple documentation clearly mention that struct doesn't support pure inheritance and it doesn't.Goldina
man that last paragraph of yours was great. I always knew that you could change constants...but then time to time I saw where you couldn't so I was baffled. This distinction made it visibleCalcareous
C
38

Assuming that we know Struct is a value type and Class is a reference type.

If you don't know what a value type and a reference type are then see What's the difference between passing by reference vs. passing by value?

Based on mikeash's post:

... Let's look at some extreme, obvious examples first. Integers are obviously copyable. They should be value types. Network sockets can't be sensibly copied. They should be reference types. Points, as in x, y pairs, are copyable. They should be value types. A controller that represents a disk can't be sensibly copied. That should be a reference type.

Some types can be copied but it may not be something you want to happen all the time. This suggests that they should be reference types. For example, a button on the screen can conceptually be copied. The copy will not be quite identical to the original. A click on the copy will not activate the original. The copy will not occupy the same location on the screen. If you pass the button around or put it into a new variable you'll probably want to refer to the original button, and you'd only want to make a copy when it's explicitly requested. That means that your button type should be a reference type.

View and window controllers are a similar example. They might be copyable, conceivably, but it's almost never what you'd want to do. They should be reference types.

What about model types? You might have a User type representing a user on your system, or a Crime type representing an action taken by a User. These are pretty copyable, so they should probably be value types. However, you probably want updates to a User's Crime made in one place in your program to be visible to other parts of the program. This suggests that your Users should be managed by some sort of user controller which would be a reference type. e.g

struct User {}
class UserController {
    var users: [User]

    func add(user: User) { ... }
    func remove(userNamed: String) { ... }
    func ...
}

Collections are an interesting case. These include things like arrays and dictionaries, as well as strings. Are they copyable? Obviously. Is copying something you want to happen easily and often? That's less clear.

Most languages say "no" to this and make their collections reference types. This is true in Objective-C and Java and Python and JavaScript and almost every other language I can think of. (One major exception is C++ with STL collection types, but C++ is the raving lunatic of the language world which does everything strangely.)

Swift said "yes," which means that types like Array and Dictionary and String are structs rather than classes. They get copied on assignment, and on passing them as parameters. This is an entirely sensible choice as long as the copy is cheap, which Swift tries very hard to accomplish. ...

I personally don't name my classes like that. I usually name mine UserManager instead of UserController but the idea is the same

In addition don't use class when you have to override each and every instance of a function ie them not having any shared functionality.

So instead of having several subclasses of a class. Use several structs that conform to a protocol.


Another reasonable case for structs is when you want to do a delta/diff of your old and new model. With references types you can't do that out of the box. With value types the mutations are not shared.

Calcareous answered 25/6, 2016 at 2:12 Comment(4)
Exactly the kind of explanation I was looking for. Nice write up :)Kaz
Very helpful controller exampleKerrykersey
@AskP I emailed mike himself and got that extra piece of code :)Calcareous
Years of experience in simple strings. Thanks.Commandant
B
30

Here are some other reasons to consider:

  1. structs get an automatic initializer that you don't have to maintain in code at all.

    struct MorphProperty {
       var type : MorphPropertyValueType
       var key : String
       var value : AnyObject
    
       enum MorphPropertyValueType {
           case String, Int, Double
       }
     }
    
     var m = MorphProperty(type: .Int, key: "what", value: "blah")
    

To get this in a class, you would have to add the initializer, and maintain the intializer...

  1. Basic collection types like Array are structs. The more you use them in your own code, the more you will get used to passing by value as opposed to reference. For instance:

    func removeLast(var array:[String]) {
       array.removeLast()
       println(array) // [one, two]
    }
    
    var someArray = ["one", "two", "three"]
    removeLast(someArray)
    println(someArray) // [one, two, three]
    
  2. Apparently immutability vs. mutability is a huge topic, but a lot of smart folks think immutability -- structs in this case -- is preferable. Mutable vs immutable objects

Billowy answered 16/1, 2015 at 22:9 Comment(6)
It's true you get automatic initialisers. You also get an empty initialiser when all the properties are Optional. But, if you have a struct in a Framework you need to actually write the initialiser yourself if you want it to be available outside internal scope.Ransell
@Ransell confirmed -- https://mcmap.net/q/15326/-how-can-i-make-the-memberwise-initialiser-public-by-default-for-structs-in-swift -- and man that is annoying.Billowy
I remember reading that there are good reasons for it, so it's expected behaviour. Can't remember why, exactly.Ransell
@Ransell there are great reasons for everything in Swift, but every time something is true in one place and not in another, the developer has to know more stuff. I guess here's where I'm supposed to say, "it's exciting to work in such a challenging language!"Billowy
Can I also add that it's not the immutability of structs that makes them useful (although it's a very good thing). You can mutate structs, But you have to mark the methods as mutating so you are explicit about what functions change their state. But their nature as value types is what is important. If you declare a struct with let you can't call any mutating functions on it. The WWDC 15 video on Better programming through value types is an excellent resource on this.Ransell
Thanks @Abizern, I never really understood this before reading your comment. For objects, let vs. var isn't much of a difference, but for structs it's huge. Thanks for pointing this out.Billowy
W
22

Some advantages:

  • automatically threadsafe due to not being shareable
  • uses less memory due to no isa and refcount (and in fact is stack allocated generally)
  • methods are always statically dispatched, so can be inlined (though @final can do this for classes)
  • easier to reason about (no need to "defensively copy" as is typical with NSArray, NSString, etc...) for the same reason as thread safety
Wellbeloved answered 15/6, 2014 at 18:38 Comment(5)
Not sure if it's outside the scope of this answer, but can you explain (or link, I guess) the "methods are always statically dispatched" point?Billowy
Sure. I can also attach a caveat to it. The purpose of dynamic dispatch is to pick an implementation when you don't know up front which one to use. In Swift, that can either be due to inheritance (might be overridden in a subclass), or due to the function being generic (you don't know what the generic parameter will be). Structs can't be inherited from and whole-module-optimization + generic specialization mostly eliminates the unknown generics, so methods can just be called directly rather than having to look up what to call. Unspecialized generics still do dynamic dispatch for structs thoughWellbeloved
Thanks, great explanation. So we're expecting more runtime speed, or less ambiguity from an IDE perspective, or both?Billowy
Mostly the former.Wellbeloved
Just a note that methods are not statically dispatched if you refer the struct via a protocol.Far
G
18

Structs are value type and Classes are reference type

  • Value types are faster than Reference types
  • Value type instances are safe in a multi-threaded environment as multiple threads can mutate the instance without having to worry about the race conditions or deadlocks
  • Value type has no references unlike reference type; therefore there is no memory leaks.

Use a value type when:

  • You want copies to have independent state, the data will be used in code across multiple threads

Use a reference type when:

  • You want to create shared, mutable state.

Further information could be also found in the Apple documentation

https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html


Additional Information

Swift value types are kept in the stack. In a process, each thread has its own stack space, so no other thread will be able to access your value type directly. Hence no race conditions, locks, deadlocks or any related thread synchronization complexity.

Value types do not need dynamic memory allocation or reference counting, both of which are expensive operations. At the same time methods on value types are dispatched statically. These create a huge advantage in favor of value types in terms of performance.

As a reminder here is a list of Swift

Value types:

  • Struct
  • Enum
  • Tuple
  • Primitives (Int, Double, Bool etc.)
  • Collections (Array, String, Dictionary, Set)

Reference types:

  • Class
  • Anything coming from NSObject
  • Function
  • Closure
Guillermoguilloche answered 3/12, 2018 at 21:14 Comment(1)
NOT safe in a multi-threaded environment If the instance passed as object is being accessed by multiple threads simultaneously, this function may still return true. Therefore, you must only call this function from mutating methods with appropriate thread synchronization. That will ensure that isKnownUniquelyReferenced(_:) only returns true when there is really one accessor, or when there is a race condition, which is already undefined behavior.Onionskin
H
14

Structure is much more faster than Class. Also, if you need inheritance then you must use Class. Most important point is that Class is reference type whereas Structure is value type. for example,

class Flight {
    var id:Int?
    var description:String?
    var destination:String?
    var airlines:String?
    init(){
        id = 100
        description = "first ever flight of Virgin Airlines"
        destination = "london"
        airlines = "Virgin Airlines"
    } 
}

struct Flight2 {
    var id:Int
    var description:String
    var destination:String
    var airlines:String  
}

now lets create instance of both.

var flightA = Flight()

var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )

now lets pass these instance to two functions which modify the id, description, destination etc..

func modifyFlight(flight:Flight) -> Void {
    flight.id = 200
    flight.description = "second flight of Virgin Airlines"
    flight.destination = "new york"
    flight.airlines = "Virgin Airlines"
}

also,

func modifyFlight2(flight2: Flight2) -> Void {
    var passedFlight = flight2
    passedFlight.id = 200
    passedFlight.description = "second flight from virgin airlines" 
}

so,

modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)

now if we print the flightA's id and description, we get

id = 200
description = "second flight of Virgin Airlines"

Here, we can see the id and description of FlightA is changed because the parameter passed to the modify method actually points to the memory address of flightA object(reference type).

now if we print the id and description of FLightB instance we get,

id = 100
description = "first ever flight of Virgin Airlines"

Here we can see that the FlightB instance is not changed because in modifyFlight2 method, actual instance of Flight2 is passes rather than reference ( value type).

Hub answered 10/5, 2016 at 12:25 Comment(3)
you never created an instance of FLightBDiversion
then why are you talking about FlightB bro? Here we can see that the FlightB instance is not changedDiversion
@ManojKarki, great answer. Just wanted to point out that you declared flightA twice when I think you wanted to declare FlightA, then FlightB.Sire
S
7

Answering the question from the perspective of value types vs reference types, from this Apple blog post it would appear very simple:

Use a value type [e.g. struct, enum] when:

  • Comparing instance data with == makes sense
  • You want copies to have independent state
  • The data will be used in code across multiple threads

Use a reference type [e.g. class] when:

  • Comparing instance identity with === makes sense
  • You want to create shared, mutable state

As mentioned in that article, a class with no writeable properties will behave identically with a struct, with (I will add) one caveat: structs are best for thread-safe models -- an increasingly imminent requirement in modern app architecture.

Sapphirine answered 5/9, 2016 at 13:19 Comment(0)
V
6

Struct vs Class

[Stack vs Heap]
[Value vs Reference type]

Struct is more preferable. But Struct does not solve all issues by default. Usually you can hear that value type is allocated on stack, but it is not always true. Only local variables are allocated on stack

//simple blocks
struct ValueType {}
class ReferenceType {}

struct StructWithRef {
    let ref1 = ReferenceType()
}

class ClassWithRef {
    let ref1 = ReferenceType()
}

func foo() {
    
    //simple  blocks
    let valueType1 = ValueType()
    let refType1 = ReferenceType()
    
    //RetainCount
    //StructWithRef
    let structWithRef1 = StructWithRef()
    let structWithRef1Copy = structWithRef1
    
    print("original:", CFGetRetainCount(structWithRef1 as CFTypeRef)) //1
    print("ref1:", CFGetRetainCount(structWithRef1.ref1)) //2 (originally 3)
    
    //ClassWithRef
    let classWithRef1 = ClassWithRef()
    let classWithRef1Copy = classWithRef1
    
    print("original:", CFGetRetainCount(classWithRef1)) //2 (originally 3)
    print("ref1:", CFGetRetainCount(classWithRef1.ref1)) //1 (originally 2)
     
}

*You should not use/rely on retainCount, because it does not say useful information

To check stack or heap

During compiling Swift Intermediate Language(SIL) can optimize you code

swiftc -emit-silgen -<optimization> <file_name>.swift
//e.g.
swiftc -emit-silgen -Onone file.swift

//emit-silgen -> emit-sil(is used in any case)
//-emit-silgen           Emit raw SIL file(s)
//-emit-sil              Emit canonical SIL file(s)
//optimization: O, Osize, Onone. It is the same as Swift Compiler - Code Generation -> Optimization Level

There you can find alloc_stack(allocation on stack) and alloc_box(allocation on heap)

[Optimization Level(SWIFT_OPTIMIZATION_LEVEL)]

Varicotomy answered 25/3, 2021 at 14:57 Comment(0)
O
3

With classes you get inheritance and are passed by reference, structs do not have inheritance and are passed by value.

There are great WWDC sessions on Swift, this specific question is answered in close detail in one of them. Make sure you watch those, as it will get you up to speed much more quickly then the Language guide or the iBook.

Orban answered 15/6, 2014 at 18:36 Comment(3)
Could you provide some links from what you mentioned? Cause on WWDC there are quite a few to choose from, I'd like to watch the one talking about this specific topicApology
For me this is a good start here: github.com/raywenderlich/…Apology
He's probably talking about this great session: Protocol-Oriented Programming in Swift. (Links: video, transcript)Flaming
E
3

I wouldn't say that structs offer less functionality.

Sure, self is immutable except in a mutating function, but that's about it.

Inheritance works fine as long as you stick to the good old idea that every class should be either abstract or final.

Implement abstract classes as protocols and final classes as structs.

The nice thing about structs is that you can make your fields mutable without creating shared mutable state because copy on write takes care of that :)

That's why the properties / fields in the following example are all mutable, which I would not do in Java or C# or swift classes.

Example inheritance structure with a bit of dirty and straightforward usage at the bottom in the function named "example":

protocol EventVisitor
{
    func visit(event: TimeEvent)
    func visit(event: StatusEvent)
}

protocol Event
{
    var ts: Int64 { get set }

    func accept(visitor: EventVisitor)
}

struct TimeEvent : Event
{
    var ts: Int64
    var time: Int64

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }
}

protocol StatusEventVisitor
{
    func visit(event: StatusLostStatusEvent)
    func visit(event: StatusChangedStatusEvent)
}

protocol StatusEvent : Event
{
    var deviceId: Int64 { get set }

    func accept(visitor: StatusEventVisitor)
}

struct StatusLostStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var reason: String

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

struct StatusChangedStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var newStatus: UInt32
    var oldStatus: UInt32

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

func readEvent(fd: Int) -> Event
{
    return TimeEvent(ts: 123, time: 56789)
}

func example()
{
    class Visitor : EventVisitor
    {
        var status: UInt32 = 3;

        func visit(event: TimeEvent)
        {
            print("A time event: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("A status event: \(event)")

            if let change = event as? StatusChangedStatusEvent
            {
                status = change.newStatus
            }
        }
    }

    let visitor = Visitor()

    readEvent(1).accept(visitor)

    print("status: \(visitor.status)")
}
Enteric answered 15/6, 2016 at 9:6 Comment(0)
R
3

In Swift, a new programming pattern has been introduced known as Protocol Oriented Programming.

Creational Pattern:

In swift, Struct is a value types which are automatically cloned. Therefore we get the required behavior to implement the prototype pattern for free.

Whereas classes are the reference type, which is not automatically cloned during the assignment. To implement the prototype pattern, classes must adopt the NSCopying protocol.


Shallow copy duplicates only the reference, that points to those objects whereas deep copy duplicates object’s reference.


Implementing deep copy for each reference type has become a tedious task. If classes include further reference type, we have to implement prototype pattern for each of the references properties. And then we have to actually copy the entire object graph by implementing the NSCopying protocol.

class Contact{
  var firstName:String
  var lastName:String
  var workAddress:Address // Reference type
}

class Address{
   var street:String
   ...
} 

By using structs and enums, we made our code simpler since we don’t have to implement the copy logic.

Representationalism answered 22/10, 2017 at 9:45 Comment(0)
A
1

Many Cocoa APIs require NSObject subclasses, which forces you into using class. But other than that, you can use the following cases from Apple’s Swift blog to decide whether to use a struct / enum value type or a class reference type.

https://developer.apple.com/swift/blog/?id=10

Assemble answered 17/11, 2016 at 11:17 Comment(0)
J
1

One point not getting attention in these answers is that a variable holding a class vs a struct can be a let while still allowing changes on the object's properties, while you cannot do this with a struct.

This is useful if you don't want the variable to ever point to another object, but still need to modify the object, i.e. in the case of having many instance variables that you wish to update one after another. If it is a struct, you must allow the variable to be reset to another object altogether using var in order to do this, since a constant value type in Swift properly allows zero mutation, while reference types (classes) don't behave this way.

Justajustemilieu answered 19/12, 2017 at 12:57 Comment(0)
T
-1

As struct are value types and you can create the memory very easily which stores into stack.Struct can be easily accessible and after the scope of the work it's easily deallocated from the stack memory through pop from the top of the stack. On the other hand class is a reference type which stores in heap and changes made in one class object will impact to other object as they are tightly coupled and reference type.All members of a structure are public whereas all the members of a class are private.

The disadvantages of struct is that it can't be inherited .

Touchback answered 23/5, 2018 at 12:35 Comment(0)
I
-1

Structures and classes are good choices for storing data and modeling behavior in your apps, but their similarities can make it difficult to choose one over the other.

Consider the following recommendations to help choose which option makes sense when adding a new data type to your app.

  • Use structures by default.
  • Use classes when you need Objective-C interoperability.
  • Use classes when you need to control the identity of the data you’re modeling.
  • Use structures along with protocols to adopt behavior by sharing implementations.

Ref- Apple documentation

Id answered 9/9, 2023 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.