FREE TRIAL: Accelerate your app development career with Hacking with Swift+! >>

What’s the difference between actors, classes, and structs?

Paul Hudson    @twostraws   

Swift provides three concrete nominal types for defining custom objects: actors, classes, and structs. Each of these works a little differently from the others, so which you use depends on the exact context you’re working in. Spoiler: you will need them all at some point.

Actors:

  1. Are reference types, so are good for shared mutable state.
  2. Can have properties, methods, initializers, and subscripts.
  3. Do not support inheritance.
  4. Automatically conform to the Actor protocol.
  5. Automatically conform to the AnyObject protocol, and can therefore conform to Identifiable without adding an explicit id property.
  6. Can have a deinitializer.
  7. Cannot have their public properties and methods directly accessed externally; we must use await.

Classes:

  1. Are reference types, so are good for shared mutable state.
  2. Can have properties, methods, initializers, and subscripts.
  3. Support inheritance.
  4. Cannot conform to the Actor protocol.
  5. Automatically conform to the AnyObject protocol, and can therefore conform to Identifiable without adding an explicit id property.
  6. Can have a deinitializer.
  7. Can have their public properties and methods directly accessed externally.

Structs:

  1. Are value types, so are copied rather than shared.
  2. Can have properties, methods, initializers, and subscripts.
  3. Do not support inheritance.
  4. Cannot conform to the Actor protocol.
  5. Cannot conform to the AnyObject protocol; if you want to add Identifiable conformance you must add an id property yourself.
  6. Cannot have a deinitializer.
  7. Can have their public properties and methods directly accessed externally.

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.

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.

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for iOS devs who want to become complete senior developers — from October 18th to 24th. Learn how to apply iOS app architecture patterns through a series of lectures and practical coding sessions.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.