Swift: Protocol vs. Struct vs. Class
These analogies are not "exactly" correct, but this is the gist of it as I understand it
Yes, Protocols are effectively like interfaces
Classes are classes, like in Java/Android, and pretty much any other language
Structs are like classes, but they are passed by-value (copied) when passing them from one variable/function to another.
If you're familiar with C# at all, it's implementation of structs is very similar.
Eg:
class Foo {
...
}
let x = Foo()
let z = x
At this point x and z both refer to the same Object in memory, there is only one Foo
object
struct Bar {
...
}
let a = Bar()
let b = a
When assigning b, a is copied (think of basically copying the memory block). At this point, there are two independent Bar
objects in memory and modifying one doesn't affect the other.
Why is this useful? Sometimes you don't want a shared reference, but mostly for performance reasons. Because structs don't have to all refer to the same object, they don't have to be allocated on the heap. They can instead often be allocated on the stack, which is much faster. Also arrays of structs can be implemented as one big contiguous block of memory which means it's much friendlier on the CPU cache if you want to iterate through it all.
Swift isn't garbage collected, but for garbage collected languages like C# this can mean the garbage collector doesn't have to deal with a lot of objects that it might otherwise have to. Even in swift the struct copying means it can avoid doing the Retain
/Release
behind the scenes neccessary for ARC, which can help a lot.
The primary use case for structs is when you have lots of immutable "simple data" like a Vector (set of 3 floating point values)
Why protocol is better than class in swift?
Lets take a downloading example.
You have a Base class FileDownloadModel, and have 3 subclasses AudioFileDownloadModel, VideoFileDownloadModel, and ImageDownloadModel.
You have a DownloadManager that takes a FileDownloadModel input and uses this model's urlToDownload property to download the file.
Later down the line you are told that there is one more model coming but it's of type UserDownloadModel which is a subclass of User, and not FileDownloadModel.
See now it becomes difficult to handle this scenario where you will have to change a lot of code to incorporate downloading methods.
How protocol oriented programming will help you here:
- Create a protocol named DownloadingFileProtocol and add
methods and properties that you need for downloading a file. eg. urlToDownload,
pathToSave, extension etc. - Implement the same protocol in FileDownloadModel and
UserDownloadModel. The benefit here is that you don't have to change a
lot of code in UserDownloadModel. You will just implement the
methods from the DownloadingFileProtocol. - If a new entity comes down the line again, you will not
change any code. Rather, you'll just implement the protocol methods. - And now your DownloadManager can take a
DownloadingFileProtocol as input instead of a specific model. As well, you can now make any model "downloadable" by having it adopt this protocol.
Identifiable protocol in Swift: class vs struct
As the documentation of Identifiable
states, it does provide a default implementation for id
for class types. However, there is no default implementation for struct
s, hence you need to add the property manually.
A class name can be the same as a protocol name in Swift?
A class name can only be the same as a protocol name if they are in different modules, or if the class is nested inside another type. Even then, it will probably be confusing.
When to switch from struct to class in swift?
is there a way to provide somekind of default implementations for functions in protocols, so i don't need to write them every time again, when confirming to a protocol?
There is indeed a way to provide default method implementations for protocol-conforming types:
protocol MyProtocol {
func myMethodRequirement()
}
extension MyProtocol {
func myMethodRequirement() {
// Default implementation.
}
}
struct Foo: MyProtocol {
func myMethodRequirement() {
// Foo-specific implementation.
}
}
struct Bar: MyProtocol {
/* Inherits default implementation instead. */
}
In your case, giving sendSomeMessage(message:)
a default implementation would look like:
extension Game {
func sendSomeMessage(message: String) {
// Default implementation here.
}
}
Any type conforming to Game
could either implement sendSomeMessage(message:)
itself (similar to override
-ing a method in a class), or use the default implementation without doing any additional work.
For more information, you can see the "Providing Default Implementations" section on protocols of the The Swift Programming Language guide.
To answer the title of your question, then, given that it is possible to do this for struct
s:
- A
class
may be useful over astruct
if you have an inheritance hierarchy multiple levels deep, which may be more complicated to express using protocol conformances - A
class
may be useful over astruct
when you need reference semantics — see:- Structures and Enumerations are Value Types and
- Classes are Reference Types
In your specific case, it doesn't immediately appear that either of these apply, but with more information, it might become obvious whether switching would be beneficial or not.
What is difference between '&' and ',' in swift about Protocol Composition
From the Swift documentation on protocols, I think &
is mainly used when you are requiring a variable to adopt to multiple protocols, ex:
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
And you use ,
when you want to adopt a custom struct/class to multiple protocols:
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
How should I reason when I have to choose between a class, struct and enum in Swift?
ChristopheD's and Jack Wu's answers are good, but I feel they don't touch on enums, or miss their importance. Swift enums are (meant to be) a full implementation of algebraic data types. Classes and structs are traditionally used to model data in object-oriented languages, but enums are usually limited to being used as a convenient way to limit the value of a variable to a limited number of possibilities. E.g. (C++):
enum MaritalStatus { Unmarried, Married, Divorced, WidowedOrWidowered };
MaritalStatus m = Unmarried;
Swift enums can do the above but they can do a lot more. Of course the Language Guide has a pretty good barcode modelling example but the best example I know of that really drives home the point of modelling data with algebraic data types is Scott Wlaschin's presentation: http://www.slideshare.net/ScottWlaschin/ddd-with-fsharptypesystemlondonndc2013
You would probably benefit from going through the whole presentation but really to 'get' the point all you need to see is slide 60 where he shows how to model a 'payment method' in a typical line-of-business app.
The examples in the presentation are in F# but F# isn't that far off from Swift and you can pretty easily map between them. E.g., the payment methods enum in Swift would look like:
enum PaymentMethod {
case cash // No extra data needed.
case cheque(Int) // Cheque #.
case card(CardType, CardNumber) // 2 pieces of extra data.
}
The point of the above is that each order's payment method can be only one of the above three methods. Anything else will not be allowed by the compiler. This is a very succinct alternative to building entire class hierarchies to model these almost trivial things.
The presentation really takes off from there and the best part is Swift can do almost everything that F# can in terms of data modelling, using optional types, etc.
Does protocol array elements passed by value or reference?
Protocols should be seen as value types because you need to explicitly tell the compiler that it is a reference type by defining it as conforming to AnyObject (which all classes conform to)
So if you have
protocol ProtocolB: AnyObject
then any type conforming to ProtocolB will be sent by reference and otherwise not.
Here is a simplified example
protocol ProtocolA {
var x: Int { get set }
}
protocol ProtocolB: AnyObject {
var y: Int { get set }
}
class ClassA: ProtocolA, ProtocolB {
var x = 0
var y = 0
}
func exampleFunction(_ object: ProtocolA) {
object.x += 2 // <-- This will generate a compilation error
}
func exampleFunction(_ object: ProtocolB) {
object.y += 2 // This is fine
}
Class does not conform to protocol, but struct does
It does not compile because your
extension MyProtocol where Self == MyClass
provides a default method only for MyClass
itself, but not for possible subclasses. Changing the constraint to
extension MyProtocol where Self: MyClass
makes the code compile. Alternatively prevent the creation of subclasses with
final class MyClass : MyProtocol {}
This is not a problem for MyStruct
because struct types cannot be inherited from in Swift.
When to use `protocol` and `protocol: class` in Swift?
Swift 4 version
AnyObject
added to a protocol definition like this
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(parameters:[String: String]?)
}
means that only a class will be able to conform to that protocol.
So given this
protocol FilterViewControllerDelegate: AnyObject {
func didSearch(parameters:[String: String]?)
}
You will be able to write this
class Foo: FilterViewControllerDelegate {
func didSearch(parameters:[String: String]?) { }
}
but NOT this
struct Foo: FilterViewControllerDelegate {
func didSearch(parameters:[String: String]?) { }
}
Swift 3 version
:class
added to a protocol definition like this
protocol FilterViewControllerDelegate: class {
func didSearch(Parameters:[String: String]?)
}
means that only a class will be able to conform to that protocol.
So given this
protocol FilterViewControllerDelegate: class {
func didSearch(Parameters:[String: String]?)
}
You will be able to write this
class Foo: FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?) { }
}
but NOT this
struct Foo: FilterViewControllerDelegate {
func didSearch(Parameters:[String: String]?) { }
}
Related Topics
API to Capture Live Photos in iOS9
Receipt Validation on iOS In-App-Purchase Returns Multiple Transaction
Exc_Bad_Access Using Ibinspectable
Core Data Taking Time to Insert Records with Fetching Entity & Set as Relationship
Programmatically Set Uipageviewcontroller Transition Style to Scroll
How Is This Slide-Up Menu from the iPhone Messages App Implemented
How Do Ruler Apps Stay Accurate on All Devices
Returning Data from Function in Firebase Observer Code Block Swift
Adding Uigesturerecognizer to Subview Programmatically in Swift
Rotate Image in Share Extension
Errortype' Is Not Convertible to 'Nserror'
Sort Alphanumeric Array, Consecutive Numbers Should Reside at Last
When Should I Use Anyobject Insted of Uibutton in Swift
Swiftui How Add Custom Modifier with Callback
iOS Swift3 Check Nil Value for Viewcontroller Object
Cannot Invoke Initializer for Type Unsafemutablepointer<Uint8>