Swift concurrency

AsyncSequence

A type that provides async, sequential, iterated access to its elements.

Overview

  • An AsyncSequence resembles the Sequence type — offering list of values you can step through one at a time.
  • An AsyncSequence may have all, some, or none of its values available when you first use it. Instead, you use await to receive values as they become available.
  • An AsyncSequence doesn’t generate or contain the values, it just defines how you access them.
  • As with Sequence, you typically iterate through an AsyncSequence with a for await-in loop. However, because the caller must potentially wait for values, you use the await keyword. Here you will see some custom AsyncSequence example that produces roll numbers for students.


for await rollNumber in RollNumberGenerator(totalStudents: 1000) {
    // TODO: -
}        

Implementation

When you define custom AsyncSequence, you will conform to 2 protocols, AsyncSequence and AsyncIteratorProtocol those will required you to defined associated type called Element, the AsyncSequence defines a makeAsyncIterator() method. This returns an instance of type AsyncIterator which defines its method next() as async, which requires caller to wait for next value with the await keyword.

struct RollNumberGenerator: AsyncSequence, AsyncIteratorProtocol {
    
    typealias Element = Int

    let totalStudents: Int
    var currentStudent = 1

    mutating func next() async -> Int? {
        guard !Task.isCancelled else {
            return nil
        }

        guard currentStudent <= totalStudents else {
            return nil
        }

        let result = currentStudent
        currentStudent += 1
        return result
    }

    func makeAsyncIterator() -> RollNumberGenerator {
        self
    }
}        

AsyncSequence Methods

  1. Return a single value
  2. Return another AsyncSequence

Single-value methods doesn’t need await-in loop, you can make single await call for example you wanna check some specific roll number

let someSpecialNumber = await RollNumberGenerator(totalStudents: 500)
.first(where: { $0 == someRollNumber })        

Methods that return another AsyncSequence for example the map(_:) method returns a AsyncMapSequence, these returned sequences don’t eagerly await the next member of the sequence, which allows the caller to decide when to start work.

In code example map(_:) method transforms each Int received from RollNumberGenerator sequence into a string and you can see doesn't require await-in loop because it returns another async sequence, but when we will iterate over mapped sequence we will need await-in loop as we used Async sequence in the beginning.

let categories = RollNumberGenerator(totalStudents: 50)
     .map {
        // Any special operation / check
        $0 + 1 % 2 == 0 ? "Section A" : "Section B"
      }
            
      for await category in categories {
         // TODO: -
      }        


要查看或添加评论,请登录

社区洞察

其他会员也浏览了