Unsure about what data type to use in swift - swift

I'm trying to write a "Restriction" of some data type, where a Restriction could be a list of Interest(enum), Experience(a range of years) or isVerified(boolean), etc. I have another class that has a property [Restriction]?.
I'm thinking about using enum but I'm not sure what's the correct/better way to construct this enum? Or maybe use struct? Any suggestions?

It's not clear from you question what "Restriction" means to you, but the way to decide is to say out loud what it means, and then use grammar to pick your types.
A struct is an "AND" type. For example:
struct Point {
let x: Double
let y: Double
}
A Point has an x coordinate AND a y coordinate. If a restriction has an interest and an experience level and a verification status, then that's a struct.
An enum is an "OR" type. For example:
enum Color {
case red
case blue
case green
}
A Color is red OR blue OR green. An enum case may also have associated data. For example:
enum Pattern {
case solid(Color)
case striped(Color, Color)
}
A Pattern is either solid with a single color OR it is striped with two colors. Notice the grammar again that helps us recognize our type: "x with y OR a with b."
Structs, classes, and tuples are all AND types, so you need some more rules to split them up. Tuples are basically anonymous structs, and they are mostly useful in Swift for short-lived, temporary values, like return values. If you find yourself wanting to create a typealias for a tuple, you probably wanted a struct instead. I find people overuse tuples (in Swift; they make more sense in other languages).
Structs are value types, while classes are reference types. The best way to understand the difference is that a value type is only its value. Any "instance" of the number 4 is identical to any other instance of the number 4. Nothing "owns" the number 4. You don't care where the number 4 came from. That's a value. The same is true for a Point. The Point (1,2) is entirely defined by the number 1 followed by the number 2. There is nothing else you can say about that Point. If your type is entirely defined by its properties, that is a good case for a struct. It should be easy to define equality between two values.
Classes are reference types. Reference types have identity. Two instances may have all the same property values, but be different "objects." When you want to ask "which one is this?" then you mean a class, not a struct. If you want to make sure two variables are "the same object" (rather than just "equal"), then you mean a class. There is a lot of pressure in Swift to use structs, but in practice, classes are extremely common, particularly in iOS development.
Thinking about what your type means, and saying it with clear language, will help you find the right types for your problem. If you're interested in a longer version of this, see Learning From Our Elders.
EDIT: Looking at your edits, I think what you're really building is a predicate. A predicate is just a function that returns yes or no given some value, and that's what I think a Restriction probably is. It looks like you want a collection of restrictions. I assume you want to then AND them all together.
A very nice way to build a predicate is with a closure. For example:
struct Element {
let interests: [String]
let experience: Int
}
struct Restriction {
let passes: (Element) -> Bool
init(hasInterest interest: String) {
passes = { $0.interests.contains(interest) }
}
init(hasAtLeastExperience years: Int) {
passes = { $0.experience >= years }
}
}
let element = Element(interests: ["fishing", "sewing"], experience: 5)
let restriction = Restriction(hasAtLeastExperience: 2)
restriction.passes(element)
With this you can easily build up groups of restrictions, apply them with AND or OR, etc.

Go with the Struct in your case because Structs are preferable if they are relatively small and copiable because copying is way safer than having multiple reference to the same instance as happens with classes. Your interest can be a list of the enum type Interest.
enum Interest {
}
struct Restriction {
let interest: [Interest]
let experience: Int
let isVerified: Bool
}

Related

Reference cycles with value types?

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).
Is there, however, a possibility of having reference cycles with value types only?
I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:
Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.
When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.
In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.
As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.
Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
Disclaimer: I'm making an (hopefully educated) guess about the inner workings of the Swift compiler here, so apply grains of salt.
Aside from value semantics, ask yourself: Why do we have structs? What is the advantage?
One advantage is that we can (read: want to) store them on the stack (resp. in an object frame), i.e. just like primitive values in other languages. In particular, we don't want to allocate dedicated space on the heap to point to. That makes accessing struct values more efficient: we (read: the compiler) always knows where exactly in memory it finds the value, relative to the current frame or object pointer.
In order for that to work out for the compiler, it needs to know how much space to reserve for a given struct value when determining the structure of the stack or object frame. As long as struct values are trees of fixed size (disregarding outgoing references to objects; they point to the heap are not of interest for us), that is fine: the compiler can just add up all the sizes it finds.
If you had a recursive struct, this fails: you can implement lists or binary trees in this way. The compiler can not figure out statically how to store such values in memory, so we have to forbid them.
Nota bene: The same reasoning explains why structs are pass-by-value: we need them to physically be at their new context.
Quick and easy hack workaround: just embed it in an array.
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
You normally cannot have a reference cycle with value types simply because Swift normally doesn't allow references to value types. Everything is copied.
However, if you're curious, you actually can induce a value-type reference cycle by capturing self in a closure.
The following is an example. Note that the MyObject class is present merely to illustrate the leak.
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
Output:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
Is there, however, a possibility of having reference cycles with value types only?
Depends on what you mean with "value types only".
If you mean completely no reference including hidden ones inside, then the answer is NO. To make a reference cycle, you need at least one reference.
But in Swift, Array, String or some other types are value types, which may contain references inside their instances. If your "value types" includes such types, the answer is YES.

in swift enum, when to use raw value and when to use associated value

Someone on StackOverflow has already provided an excellent answer to the question: what is the difference between raw value and associated value in swift.
Difference between associated and raw values in swift enumerations
However, the question did not include information on when to use raw value and when to associated value. This is the part I'm a little confused about. It would be greatly if someone can explain it to everyone. I think this is a problem that a lot of beginners to swift would have as well.
You pick one that logically matches your business case/requirement/feature/model BETTER.
You should look at the anatomy of swift Enum and try to find cases/situations/options in real world which match one of the two Enum variants. I'll give you an example for both.
RAW VALUE
enum CountryAcronyms: String {
case UnitedKingdom = "UK"
case Germany = "DE"
case Australia = "AU"
}
Here you are dealing with cases are all the same category of things which is Country and each country can be represented by a single one acronym, that is of type String. The important fact here is that the underlying type for acronyms all across is String.
So "RawValue"..in other words is when you have ONE AND THE SAME underlying type chosen to represent EACH case. The when you want to extract the underlying value of the underlying type, you use the rawValue accessor.
ASSOCIATED VALUE
enum Trip {
case Abroad(Airplane, Taxi, Foot)
case Grandma(Tube, Foot)
case McDonalds(Car)
case MountEverest(Ski, Foot)
}
Here we have a set of cases and each represent also one thing - a Trip, but the associated types in this enum represent THE MEANS (this is what we chose..that's it! Perhaps there is a business case or a design ..or simply customer wants it..) and Since the means DIFFER for each case, we associate a unique type (in this case tuples with 1 or more types) that is able to represent the means. Since we wanted to represent something like this we couldn't chose the previous Enum approach because we would have no way to express various means.
If you want a case of an enum to stand for one simple constant literal value, use a raw value.
enum PepBoy : String {
case Manny = "Manny"
case Moe = "Moe"
case Jack = "Jack"
}
If you want a case of an enum to carry arbitrary value(s) of a predefined type, use an associated type.
enum Error : ErrorType {
case Number(Int)
case Message(String)
}
Usage examples:
let pb : PepBoy = .Manny
print(pb.rawValue) // "Manny" [and only ever "Manny", if the case is Manny]
do {
let e = Error.Message("You screwed up") // attach a message [any message]
throw e
} catch Error.Message(let whatHappened) { // retrieve the message
print(whatHappened) // "You screwed up"
} catch {
}

Generic Random Function in Swift

I have researched and looked into many different random function, but the downside to them is that they only work for one data type. I want a way to have one function work for a Double, Floats, Int, CGFloat, etc. I know I could just convert it to different data types, but I would like to know if there is a way to have it done using generics. Does someone know a way to make a generic random function using swift. Thanks.
In theory you could port code such as this answer (which is not necessarily a great solution, depending on your needs, since UInt32.max is relatively small)
extension FloatingPointType {
static func rand() -> Self {
let num = Self(arc4random())
let denom = Self(UInt32.max)
// this line won’t compile:
return num / denom
}
}
// then you could do
let d = Double.rand()
let f = Float.rand()
let c = CGFloat.rand()
Except… FloatingPointType doesn’t conform to a protocol that guarantees operators like /, + etc (unlike IntegerType which conforms to _IntegerArithmeticType).
You could do this manually though:
protocol FloatingPointArithmeticType: FloatingPointType {
func /(lhs: Self, rhs: Self) -> Self
// etc
}
extension Double: FloatingPointArithmeticType { }
extension Float: FloatingPointArithmeticType { }
extension CGFloat: FloatingPointArithmeticType { }
extension FloatingPointArithmeticType {
static func rand() -> Self {
// same as before
}
}
// so these now work
let d = Double.rand() // etc
but this probably isn’t quite as out-of-the-box as you were hoping (and no doubt contains some subtle invalid assumption about floating-point numbers on my part).
As for something that works across both integers and floats, the Swift team have mentioned on their mail groups before that the lack of protocols spanning both types is a conscious decision since it’s rarely correct to write the same code for both, and that’s certainly the case for generating random numbers, which need two very different approaches.
Before you get too far into this, think about what you want the behavior of a type-agnostic random function to be, and whether that's something that you want. It sounds like you're proposing something like this:
// signature only
func random<T>() -> T
// example call sites, with specialization by inference from declared result type
let randInt: Int = random()
let randFloat: Float = random()
let randDouble: Double = random()
let randInt64: Int = random()
(Note this syntax is sort of fake: without a parameter of type T, the implementation of random<T>() can't determine which type to return.)
What do you expect the possible values in each of these to be? Is randInt always a value between zero and Int.max? (Or maybe between zero and UInt32.max?) Is randFloat always between 0.0 and 1.0? Should randDouble actually have a larger count of possible values than randFloat (per the increased resolution between 0.0 and 1.0 of the Double type)? How do you account for the fact that Int is actually Int32 on 32-bit systems and Int64 on 64-bit hardware?
Are you sure it makes sense to have two (or more) calls that look identical but return values in different ranges?
Second, do you really want "arbitrarily random" random number generation everywhere in your app/game? Most use of RNGs is in game design, where typically there are a couple of important things you want in your RNG before you get your product past the prototyping stage:
Independence: I've seen games where you could learn to predict the next "random" enemy encounter based on recent "random" NPC chitchat/emotes. If you're using random elements in multiple gameplay systems, you don't want
Determinism: If you want to be able to reproduce a sequence of game events — either for testing/debugging or for consistent results between clients in a networked game — you don't want to be using a random function where you can't control that sequence. arc4random doesn't let you control the initial seed, and you have no control over the sequence because you don't know what other code in your process (library code, or just other code of your own that you forgot about) is also pulling numbers from the generator.
(If you're not making a game... much of this still applies, though it may be less important. You still don't want to be re-running your test case until the heat death of the universe trying to randomly find the same bug that one of your users reported.)
In iOS 9 / OS X 10.11 / tvOS, GameplayKit provides a suite of randomization tools to address these issues.
let randA = GKARC4RandomSource()
let someNumbers = (0..<1000).map { _ in randA.nextInt() }
let randB = GKARC4RandomSource()
let someMoreNumbers = (0..<1000).map { _ in randB.nextInt() }
let randC = GKARC4RandomSource(seed: randA.seed)
let evenMoreNumbers = (0..<1000).map { _ in randC.nextInt() }
Here, someMoreNumbers is always nondeterministic, no matter what happens in the generation of someNumbers or what other randomization activity happens on the system. And evenMoreNumbers is the exact same sequence of numbers as someNumbers.
Okay, so the GameplayKit syntax isn't quite what you want? Well, some of that is a natural consequence of having to manage RNGs as objects so that you can keep them independent and deterministic. But if you really want to have a super-simple random() call that you can slot in wherever needed, regardless of return type, and be independent and deterministic...
Here's one possible recipe for that. It implements random() as a static function on a type extension, so that you can use type-inference shorthand to write it; e.g.:
// func somethingThatTakesAnInt(a: Int, andAFloat Float: b)
somethingThatTakesAnInt(.random(), andAFloat: random())
The first parameter automatically calls Int.random() and the second calls Float.random(). (This is the same mechanism that lets you use shorthand for referring to enum cases, or .max instead of Int.max, etc.)
And it makes the type extensions private, with the idea that different source files will want independent RNGs.
// EnemyAI.swift
private extension Int {
static func random() -> Int {
return EnemyAI.die.nextInt()
}
}
class EnemyAI: NSObject {
static let die = GKARC4RandomSource()
// ...
}
// ProceduralWorld.swift
private extension Int {
static func random() -> Int {
return ProceduralWorld.die.nextInt()
}
}
class ProceduralWorld: NSObject {
static let die = GKARC4RandomSource()
// ...
}
Repeat with extensions for more types as desired.
If you add some breakpoints or logging to the different random() functions you'll see that the two implementations of Int.random() are specific to the file they're in.
Anyway, that's a lot of boilerplate, but perhaps it's good food for thought...
Personally, I'd probably write individual implementations for each thing you wanted. There just aren't that many, and it's a lot safer and more flexible. But… sure, you can do this. Just create a random bit pattern and say "that's a number."
func randomValueOfType<T>(type: T.Type) -> T {
let size = sizeof(type)
let bits = UnsafeMutablePointer<T>.alloc(1)
arc4random_buf(bits, size)
return bits.memory
}
(This is technically "that's a something" but if you pass it something other than number-like types, you'll probably crash because most random bit patterns aren't a legal object.)
I believe every possible bit pattern will generate a legal IEEE 754 number, but "legal" may be more complex than you're thinking. A "totally random" float would rightly include NaN (not-a-number) which will show up reasonably often in your results.
There are some other special cases like the infinities and negative zero, but in practice those should never occur. Any single bit pattern showing up in a random choice of 32-bits is effectively zero. There are lots of NaN bit patterns, so it shows up a lot.
And that's the problem with this whole approach. If your random generator can accept that NaN shows up, then it's probably testing real floating point. But if you're testing real floating point, you really want to be checking the edge cases like infinity and negative zero. But if you don't want to include NaN, then you don't really mean "a random Float" you mean "a random Real number that can be expressed as a Float." There's no type for that, so you would need to write specific logic to handle it, and if you're doing that, you might as well write a specialized random generator for each type.
But this function is probably still a useful foundation for building that. You could just generate values until one is a legal number (NaN doesn't show up that often, so you'll almost certainly get it in less than 2 tries).
This kind of emphasizes the point Airspeed Velocity made about why there's no generic "number" protocol. You usually can't just treat floating point numbers like integers. They just work differently, and you very often need to think about that fact.

What's the best way to declare a list of scalar values in Swift

I was wondering: What is the best way to declare a non-ordered list of scalar values in Swift, that are fully backed by a symbol and are liable to be checked by the compiler?
Let's say I want to declare a list of LetterSpacing values that I want to access and use in my code via their symbols.
My understanding is that I should declare an swift enum like this:
enum LetterSpacing: Double {
case Short = 1.0
case Medium = 2.0
case Large = 3.0
}
This works fine and gets compiler checks but the annoying part is that I need to LetterSpacing.XXX.rawValue each time to access the underlying value. The .rawValue bothers me a bit to have to specify this everywhere.
I suppose it wouldn't make sense or would be inappropriate to declare a struct with three static let Short = 1.0 etc..
So, how would you handle such cases? Is it possible to add somekind of protocol/extension swift magic to the existing types to be able to have the Short enum act as its own value? (i.e. let size = LetterSpacing.Short would be of type Double and have a value of 1.0)
The enum would be preferred for multiple reasons.
First, the enum actually ends up with a smaller memory footprint. This is because Swift optimizing enum values into a single byte (no matter what the raw value is), and we only get the full value out of it when we call rawValue on the enum value. Paste the following code into a playground to see:
struct LetterSpacingS {
static let Short: Double = 1.0
}
enum LetterSpacingE: Double {
case Short = 1.0
}
sizeofValue(LetterSpacingS.Short)
sizeofValue(LetterSpacingE.Short)
The double is 8 bytes, while the enum is just 1.
Second, the importance of the first point extends beyond just memory footprint. It can apply to the execution efficiency of our program as well. If we want to compare two values from our struct, we're comparing 8 bytes. If we want to compare two of our enum values, we comparing just a single byte. We have 1/8th as many bytes to compare in this specific case. And this is just with a double. Consider that Swift enums can also have a string as a backing type. Comparing two strings can be extraordinarily expensive versus just comparing the single byte they're hidden behind in an enum.
Third, using the enum, we're not comparing floating point numbers, which you really don't want to do, generally speaking.
Fourth, using the enum gives us some type safety that we can't get with the struct of constants. All the struct of constants does is let us define a handful of predefined constants to use.
struct LetterSpacingS {
static let Short = 1.0
static let Medium = 2.0
static let Long = 3.0
}
But now what would a method look like that expects one of these values?
func setLetterSpacing(spacing: Double) {
// do stuff
}
And now what happens when Joe-Coder comes in and does:
foo.setLetterSpacing(-27.861)
Nothing's stopping him. It takes a double, any double. This might not be so common, but if this is in a library you're distributing, you are leaving yourself open to questions and comments like "When I pass a value of 5.0 in, it doesn't look right at all!"
But compare this to using the enum.
func setLetterSpacing(spacing: LetterSpacing) {
// do stuff
}
And now, we only get the three predefined choices for what to pass into this argument.
And outside of your internal use for the values held by the enum, you should have to use rawValue too much.
The fifth reason isn't a strong reason for using an enum over a struct, but mostly just a point to make to eliminate one of the reasons suggested for using a struct over an enum. Swift enums can be nested in other types, and other types can be nested in Swift enums. You don't have to use a struct to get nested types.
I don't see why creating a Struct with three static constants would be inappropriate. I see a lot of Swift code (also from Apple) that does this.
Structs lets you create nice hierarchies:
struct Style {
struct Colors {
static let backgroundColor = UIColor.blackColor()
...
}
struct LetterSpacing {
static let Short = 1.0
}
...
}

Why Choose Struct Over Class?

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?
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.
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)
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)
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.
Here are some other reasons to consider:
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...
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]
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
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
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
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).
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.
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 SIL(Swift Intermediate Language) 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)]
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.
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)")
}
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.
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
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.
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 .
Structure and class are user defied data types
By default, structure is a public whereas class is private
Class implements the principal of encapsulation
Objects of a class are created on the heap memory
Class is used for re usability whereas structure is used for grouping
the data in the same structure
Structure data members cannot be initialized directly but they can be
assigned by the outside the structure
Class data members can be initialized directly by the parameter less
constructor and assigned by the parameterized constructor