Swift - toant-dev/toandev.github.io GitHub Wiki
https://www.hackingwithswift.com/articles/233/whats-new-in-swift-5-5
func listPhotos(inGallery name: String) async -> [String] {
await Task.sleep(2 * 1_000_000_000) // Two seconds
return ["IMG001", "IMG99", "IMG0404"]
}
let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
print(line)
}
let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])
let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
// ----------- concurrent vs paralle --------------------
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])
let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
let task = Task { () -> String in
print("Starting")
await Task.sleep(1_000_000_000)
try Task.checkCancellation()
return "Done"
}
// The task has started, but we'll cancel it while it sleeps
task.cancel()
await withTaskGroup(of: Data.self) { taskGroup in
let photoNames = await listPhotos(inGallery: "Summer Vacation")
for name in photoNames {
taskGroup.async { await downloadPhoto(named: name) }
}
}
SE-0306 introduces actors, which are conceptually similar to classes that are safe to use in concurrent environments. This is possible because Swift ensures that mutable state inside your actor is only ever accessed by a single thread at any given time, which helps eliminate a variety of serious bugs right at the compiler level.
Actors handle their synchronization internally
actor SafeCollector {
var deck: Set<String>
init(deck: Set<String>) {
self.deck = deck
}
func send(card selected: String, to person: SafeCollector) async -> Bool {
guard deck.contains(selected) else { return false }
deck.remove(selected)
await person.transfer(card: selected)
return true
}
func transfer(card: String) {
deck.insert(card)
}
}
class NewDataController {
@MainActor func save() {
print("Saving data…")
}
}
With @MainActor we can guarantee that save() is always called on the main thread as if we specifically ran it using DispatchQueue.main. No need to check Thread.isMainThread
SE-0302 adds support for “sendable” data, which is data that can safely be transferred to another thread. This is accomplished through a new Sendable protocol, and an @Sendable attribute for functions.
Many things are inherently safe to send across threads:
- All of Swift’s core value types, including Bool, Int, String, and similar.
- Optionals, where the wrapped data is a value type.
- Standard library collections that contain value types, such as Array or Dictionary<Int, String>.
- Tuples where the elements are all value types.
- Metatypes, such as String.self.
func lazyTest() {
print("Before lazy")
lazy var greeting = printGreeting(to: "Paul")
print("After lazy")
print(greeting)
}
let first: CGFloat = 42
let second: Double = 19
let result = first + second
print(result)
enum Weather: Codable {
case sun
case wind(speed: Int)
case rain(amount: Int, chance: Int)
}
@propertyWrapper
struct Clamped<T: Comparable> {
let wrappedValue: T
init(wrappedValue: T, range: ClosedRange<T>) {
self.wrappedValue = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
func setScore2(@Clamped(range: 0...100) to score: Int) {
print("Setting score to \(score)")
}
setScore2(to: 50) // OK = 50
setScore2(to: -50) // OK = 0
setScore2(to: 500) // OK = 100