In the latest edition of swift programming language, there are some changes in the latest version of Swift 5.5
- What’s new in Swift 5.5?
- are these changes will impact the current syntax or code?
- is the changes are minor or major?
nonisolated
To conform synchronous protocol requirements it uses Non-isolated declarations :
actor Account: Hashable {
let idNumber: Int
var balance: Double
nonisolated func hash(into hasher: inout Hasher) { // okay, non-isolated satisfies synchronous requirement
hasher.combine(idNumber) // okay, can reference idNumber from outside the let
hasher.combine(balance) // error: cannot synchronously access actor-isolated property
}
}
withUnsafeContinuation and withUnsafeThrowingContinuation
Async functions can now be suspended using the withUnsafeContinuation and withUnsafeThrowingContinuation functions. These both take a closure and then suspend the current async task, executing that closure with a continuation value for the current task.
The program must use that continuation at some point in the future to resume the task, passing in a value or error, which then becomes the result of the withUnsafeContinuation call in the resumed task.
struct MyValue {
}
struct MyStruct {
subscript(a: MyValue.Type) -> Int { get { … } }
}
func test(obj: MyStruct) {
let _ = obj[MyValue]
}
Accepting subscripts with MyValue as an argument was an oversight because MyValue requires explicit .self to reference its metatype, so correct syntax would be to use obj[MyValue.self].
async and throws
async and/or throws, by writing one or both of those keywords between the get and {. Thus, these members can now make asynchronous calls or throw errors in the process of producing a value:
class BankAccount: FinancialAccount {
var manager: AccountManager?
var lastTransaction: Transaction {
get async throws {
guard manager != nil else { throw BankError.notInYourFavor }
return await manager!.getLastTransaction()
}
}
subscript(_ day: Date) -> [Transaction] {
get async {
return await manager?.getTransactions(onDay: day) ?? []
}
}
}
protocol FinancialAccount {
associatedtype T
var lastTransaction: T { get async throws }
subscript(_ day: Date) -> [T] { get async }
}
await and try
extension BankAccount {
func meetsTransactionLimit(_ limit: Amount) async -> Bool {
return try! await self.lastTransaction.amount < limit
// ^~~~ this access is async & throws
}
}
func hadWithdrawlOn(_ day: Date, from acct: BankAccount) async -> Bool {
return await !acct[day].allSatisfy { $0.amount >= Amount.zero }
// ^~~~~ this access is async
}
instance isolatation
a new kind of type that isolates its instance data to protect it from concurrent access.
actor Counter {
var value = 0
func increment() {
value = value + 1
}
}
func useCounter(counter: Counter) async {
print(await counter.value) // interaction must be async
await counter.increment() // interaction must be async
}
rethrows
The determination of whether a call to a rethrows function can throw now considers default arguments of Optional type.
func foo(_: (() throws -> ())? = nil) rethrows {}
foo() // no 'try' needed
However, it also meant that the following was accepted, even though the call to foo() can throw and the call site is not marked with try:
func foo(_: (() throws -> ())? = { throw myError }) rethrows {}
foo() // 'try' should be required here
The new behavior is that the first example is accepted because the default argument is syntactically written as nil, which is known not to throw.
The second example is correctly rejected on account of missing a try since the default argument can throw.
Property wrappers
Property wrappers can now be applied to function and closure parameters:
@propertyWrapper
struct Wrapper {
var wrappedValue: Value
var projectedValue: Self { return self }
init(wrappedValue: Value) { … }
init(projectedValue: Self) { … }
}
func test(@Wrapper value: Int) {
print(value)
print($value)
print(_value)
}
test(value: 10)
let projection = Wrapper(wrappedValue: 10)
test($value: projection)
The callsite can pass a wrapped value or a projected value, and the property wrapper will be initialized using init(wrappedValue:) or init(projectedValue:).
Self
It is now possible to use leading-dot syntax in generic contexts to access static members of protocol extensions where Self is constrained to a fully concrete type:
public protocol ToggleStyle { … }
public struct DefaultToggleStyle: ToggleStyle { … }
extension ToggleStyle where Self == DefaultToggleStyle {
public static var default: Self { .init() }
}
struct Toggle {
func applyToggle(_ style: T) { … }
}
Toggle(…).applyToggle(.default)
Whenever a reference to Self does not impede the usage of a protocol as a value type, or a protocol member on a value of protocol type, the same is now true for references to [Self] and [Key : Self]:
protocol Copyable {
func copy() -> Self
func copy(count: Int) -> [Self]
}
func test(c: Copyable) {
let copy: Copyable = c.copy() // OK
let copies: [Copyable] = c.copy(count: 5) // also OK
}
asynchronous programming
It is now using async/await and Asynchronous functions can be defined using async:
func loadWebResource(_ path: String) async throws -> Resource { … }
func decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image
func dewarpAndCleanupImage(_ i : Image) async -> Image
Above Calls to async functions may suspend. it means that it gives up the thread on which they are executing again later.
The potential for suspension on asynchronous calls requires the await keyword, similarly to the way in which try acknowledges a call to a throws function.
func processImageData() async throws -> Image {
let dataResource = try await loadWebResource("dataprofile.txt")
let imageResource = try await loadWebResource("imagedata.dat")
let imageTmp = try await decodeImage(dataResource, imageResource)
let imageResult = await dewarpAndCleanupImage(imageTmp)
return imageResult
}
The ‘lazy’ keyword now works in local contexts, making the following valid.
func test(useIt: Bool) {
lazy var result = getPotentiallyExpensiveResult()
if useIt {
doIt(result)
}
}
async
An Objective-C method that delivers its results asynchronously via a completion handler block will be translated into an async. This method is directly returns the result (or throws):
(void)fetchShareParticipantWithUserRecordID:(CKRecordID *)userRecordID
completionHandler:(void (^)(CKShareParticipant * _Nullable, NSError * _Nullable))completionHandler;
This is translated into an async throws method. Therefore it returns the participant instance:
func fetchShareParticipant(
withUserRecordID userRecordID: CKRecord.ID
) async throws -> CKShare.Participant
Swift callers can invoke this async method within an await expression:
guard let participant = try? await container.fetchShareParticipant(withUserRecordID: user) else {
return nil
}
asyncsequence
To traverse asynchronous sequences in asynchronous code it uses “for”:
for try await line in myFile.lines() {
// Do something with each line
}
Asynchronous for loops use asynchronous sequences, defined by the protocol AsyncSequence and its corresponding AsyncIterator.
Thank you for you valuable time !
Please refer Swift Change log for more informations !
Discover more from CODE t!ps
Subscribe to get the latest posts sent to your email.