What’s the difference between actors, classes, and structs?
What’s the difference between actors, classes, and structs? 관련
Updated for Xcode 15
Swift provides four concrete nominal types for defining custom objects: actors, classes, structs, and enums. Each of these works a little differently from the others, but the first three might seem similar so it’s worth spending a little time clarifying what they have in common and where their differences are.
Tips
Ultimately, which you use depends on the exact context you’re working in, and you will need them all at some point.
Actors:
- Are reference types, so are good for shared mutable state.
- Can have properties, methods, initializers, and subscripts.
- Do not support inheritance.
- Automatically conform to the
Actor
protocol. - Automatically conform to the
AnyObject
protocol, and can therefore conform toIdentifiable
without adding an explicitid
property. - Can have a deinitializer.
- Cannot have their public properties and methods directly accessed externally; we must use
await
. - Can execute only one method at a time, regardless of how they are accessed.
Classes:
- Are reference types, so are good for shared mutable state.
- Can have properties, methods, initializers, and subscripts.
- Support inheritance.
- Cannot conform to the
Actor
protocol. - Automatically conform to the
AnyObject
protocol, and can therefore conform toIdentifiable
without adding an explicitid
property. - Can have a deinitializer.
- Can have their public properties and methods directly accessed externally.
- Can potentially be executing severals methods at a time.
Structs:
- Are value types, so are copied rather than shared.
- Can have properties, methods, initializers, and subscripts.
- Do not support inheritance.
- Cannot conform to the
Actor
protocol. - Cannot conform to the
AnyObject
protocol; if you want to addIdentifiable
conformance you must add anid
property yourself. - Cannot have a deinitializer.
- Can have their public properties and methods directly accessed externally.
- Can potentially be executing severals methods at a time.
You might think the advantages of actors are such that they should be used everywhere classes are currently used, but that is a bad idea. Not only do you lose the ability for inheritance, but you’ll also cause a huge amount of pain for yourself because every single external property access needs to use await
.
However, there are certainly places where actors are a natural fit. For example, if you were previously creating serial queues to handle specific workflows, they can be replaced almost entirely with actors – while also benefiting from increased safety and performance. So, if you have some work that absolutely must work one at a time, such as accessing a database, then trying converting it into something like a database actor.
There is one area in particular where using actors rather than classes is going to cause problems, so I really can’t say this clearly enough:
Do not use actors for your SwiftUI data models. You should use a class that conforms to the ObservableObject
protocol instead. If needed, you can optionally also mark that class with @MainActor
to ensure it does any UI work safely, but keep in mind that using @StateObject
or @ObservedObject
automatically makes a view’s code run on the main actor. If you desperately need to be able to carve off some async work safely, you can create a sibling actor – a separate actor that does not use @MainActor
, but does not directly update the UI.