Async Sequence를 지원하는 API
- URL
- FileHandle
- URLSession
- NotificationCenter
또한 우리가 알고있는 고차함수
map, compactMap, filter, first, prefix, zip 등을 활용할 수 있다.
1. FileHandle
URL은 직전에 했기에 FileHandle을 사용해본다.
우선 File을 사용하기 위해 경로 설정을 해줘야한다.
let paths = Bundle.main.paths(forResourcesOfType: "txt", inDirectory: nil)
let fileHandle = FileHandle(forReadingAtPath: paths[0])
그리고 우린 파일 경로가 하나이기에 index를 0으로 해준다.
Task {
for try await line in fileHandle!.bytes {
print(line)
}
}
/*
74
111
104
110
10
77
97
114
121
10
10
*/
각 라인별 바이트가 나온다.
2. URL
물론 파일도 URL을 통해서 읽을 수가 있다.
Task {
let url = URL(fileURLWithPath: paths[0])
for try await line in url.lines {
print(line)
}
}
/*
John
Mary
*/
한줄씩 읽는다.
3. URLSession
let url = URL(string: "https://www.google.com")!
Task {
let (bytes, _) = try await URLSession.shared.bytes(from: url)
for try await byte in bytes {
print(byte)
}
}
/*
102
117
110
99
116
105
111
너무 길어서 후략
*/
4, Notification Center
Task {
let center = NotificationCenter.default
let _ = await center.notifications(named: UIApplication.didEnterBackgroundNotification).first {
guard let key = ($0.userInfo?["Key"]) as? String else { return false }
return key == "SomeValue"
}
}
위의 코드는 앱이 Background드로 들어가는 상태일때
알림 중에서 userInfo에 “Key”라는 값이 있고, 그 값이 “SomeValue”와 일치하는 첫 번째 알림을 찾는다. 조건이 만족되면 해당 알림을 반환하고, 그렇지 않으면 다음 알림을 기다린다.
기존 Callback 또는 Handler를 AsyncSequence로 변환하기 위한 AsyncStream 활용
class BitcoinPriceMonitor {
var price: Double = 0.0
var timer: Timer?
var priceHandler: (Double) -> Void = { _ in }
@objc func getPrice() {
priceHandler(Double.random(in: 20000...40000))
}
func startUpdating() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(getPrice), userInfo: nil, repeats: true)
}
func stopUpdating() {
timer?.invalidate()
}
}
Class를 하나 만들어 준다.
var priceHandler: (Double) -> Void = { _ in }
initializing을 하기 위해 위와 같이 만들어 준다.
let bitcoinPriceMonitor = BitcoinPriceMonitor()
bitcoinPriceMonitor.priceHandler = {
print($0)
}
bitcoinPriceMonitor.startUpdating()
/*
21045.523121187536
20192.72163692504
34665.56744521043
29779.326709794215
35158.70015038814
25228.016388562803
33050.03001821222
23941.779428903712
29135.677928071524
22594.94240977771
*/
1초단위로 이렇게 출력이 된다.
이제 AsyncStream을 사용해서 만들어본다.
AsyncStream(Double.self) { continuation in
이렇게 closure형태로 쓰는데 괄호안에는 Return Type을 작성해준다.
그리고 하나 더 특이점이라면 continuation뒤에 yield를 사용해준다.
대기 중인 작업을 중단 지점에서 주어진 결과의 성공 값을 반환하며 정상적으로 재개시킨다.
즉, 이전 작업에서 성공했던 값을 반환하면서 다음 값을 기다리는 상태로 전환한다. 라고 생각하면 될듯.
let bitcoinPriceStream = AsyncStream(Double.self) { continuation in
let bitcoinPriceMonitor = BitcoinPriceMonitor()
bitcoinPriceMonitor.priceHandler = { result in
print("sending: \(result)")
continuation.yield(result)
print("sent: \(result)")
}
//continuation.onTermination = { _ in }
bitcoinPriceMonitor.startUpdating()
}
Task {
for await bitcoinPrice in bitcoinPriceStream {
print("received: \(bitcoinPrice)")
}
}
이해를 돕고자 print를 달아주었다.
sending: 38041.31187779264
received: 38041.31187779264
sent: 38041.31187779264
sending: 25532.912948323756
received: 25532.912948323756
sent: 25532.912948323756
sending: 32142.705564361964
received: 32142.705564361964
sent: 32142.705564361964
sending: 36629.111843853
sent: 36629.111843853
received: 36629.111843853
이런식으로 결과가 나온다.
PREVIOUSAsync/Await (9)
NEXTAsync/Await (11)