In WWDC21, Apple announced a new way of writing thread-safe, isolated code, which is especially useful for the new beginners. The actor is a new concrete nominal type in Swift, just like a class or an enum. They are reference types, just like classes but they do not support subclassing and they automatically conform to the Actor protocol.
Prime features of an actor:
- Reference type, just like a class, but they cannot inherit another actor, do not support override or final keywords
- Can conform to other protocols
- They can have properties, methods and extensions, just like classes
- The main objective of an actor is to isolate it’s mutable properties and to give compile-time errors when those properties are accessed from the outside. This new feature helps the programmer to identify and fix possible data races when some mutable properties are accessed from another places (and possibly from another threads.)
Quick overview of a protocol conforming to Actor protocol:
/// Actors can inherit protocols, but the protocol needs
/// to conform to `Actor` protocol
protocol SomeActor: Actor {
var id: UUID { get }
var name: String { get set }
func getName() -> String
}
So, just like a class or a struct, actor can inherit protocol and it’s requirements like properties and functions.
actor SomeActorImpl: SomeActor {
let id: UUID
var name: String
init(name: String) {
self.id = UUID()
self.name = name
}
func getName() -> String {
return name
}
}
Actors can conform to Equatable protocol, the == method is static, which is safe, but the comparing left and right hand side should compare only constants, not variables. So, it is useful for an actor to have a constant identifier property.
extension SomeActorImpl: Equatable {
static func == (lhs: SomeActorImpl,
rhs: SomeActorImpl) -> Bool {
return lhs.id == rhs.id
}
}
The dark side of an actor.
All methods and properties in actor are isolated by default. As mentioned before, that means that mutables cannot be accessed from the outside of an actor. There is a way of making parts of the code non-isolated.
Non-isolated methods can access other non-isolated properties, methods or constants (which are immutable states), however they cannot access isolated actor methods, they need to use await keyword.
nonisolated keyword is particularly useful when using protocol conformance, like for an example, Hashable.
Hashable protocol conformance have methods that require access from the outside, so there is no way in getting around that…
extension SomeActorImpl: Hashable {
nonisolated
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
nonisolated
var hashValue: Int {
return id.hashValue
}
}
In conclusion, actors just provide another way of dealing with the thread-safety. Maybe they are not very useful in legacy code, but they sure provide a more quick resolve when writing new, simple data providers, like for example, data holders that fetch periodically from web or locally stored data.
WWDC Link: https://developer.apple.com/videos/play/wwdc2021/10133/
Comments
Post a Comment