7

In the "Platforms State of the Union" video of WWDC2021 at 28:00 it was mentioned that

[Apple] even added support for asynchronously iterating line-by-line through a file

in Foundation for macOS 12/iOS 15 and Swift 5.5.

What is that new API, how can I now asynchronously iterate line-by-line through a file?

YourMJK
  • 1,429
  • 1
  • 11
  • 22
  • https://developer.apple.com/videos/play/wwdc2021/10132/ ? – Larme Jun 10 '21 at 11:19
  • @Larme Already watched that, there wasn't any mention of the API I'm looking for. – YourMJK Jun 10 '21 at 11:22
  • or https://developer.apple.com/videos/play/wwdc2021/101/ (at 1:38)? Its await/async? It's not really an API, it's in the language I'd say. And the related topic on the previous link: https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md https://github.com/apple/swift-evolution/blob/main/proposals/0300-continuation.md etc. ? – Larme Jun 10 '21 at 11:23
  • Pretty sure it's an API, since in context they mentioned other APIs before that. But I'd also welcome an answer explaining how to do this yourself with async/await – YourMJK Jun 10 '21 at 11:26
  • Are you talking about [this](https://developer.apple.com/documentation/foundation/urlsession/asyncbytes/3767336-lines)? – Sweeper Jun 10 '21 at 11:40
  • @Sweeper Maybe? Seems a bit like it, but that's just for `URLSession`. I would have expected something for `FileHandle`, `String` and/or `Data` so it can be used for local files. – YourMJK Jun 10 '21 at 11:46
  • 2
    @YourMJK There is one for `FileHandle` too, but in the documentation it is stated that it is recommended to use the `URLSession` version instead. – Sweeper Jun 10 '21 at 11:48

1 Answers1

11

The main thing they added that enables this, is AsyncSequence. AsyncSequence is like Sequence, but its Iterator.next method is async throws.

Specifically, you can use URLSession.AsyncBytes.lines to get an AsyncSequence of the lines in a file.

Suppose you are in an async throws method, you can do:

let (bytes, response) = try await URLSession.shared.bytes(from: URL(string: "file://...")!)
for try await line in bytes.lines {
    // do something...
}

Note that there is also FileHandle.AsyncBytes.lines, but in the documentation it says:

Rather than creating a FileHandle to read a file asynchronously, you can instead use a file:// URL in combination with the async-await methods in URLSession. These include the bytes(for:delegate:) and bytes(from:delegate:) methods that deliver an asynchronous sequence of bytes, and data(for:delegate:) and data(from:delegate:) to return the file’s entire contents at once.

Sweeper
  • 213,210
  • 22
  • 193
  • 313