Async/Await (10)
Async Sequence를 지원하는 API
- URL
- FileHandle
- URLSession
- NotificationCenter
또한 우리가 알고있는 고차함수
map, compactMap, filter, first, prefix, zip 등을 활용할 수 있다.
1. FileHandle
URL은 직전에 했기에 FileHandle을 사용해본다.
우선 File을 사용하기 위해 경로 설정을 해줘야한다.
1
2
let paths = Bundle.main.paths(forResourcesOfType: "txt", inDirectory: nil)
let fileHandle = FileHandle(forReadingAtPath: paths[0])
그리고 우린 파일 경로가 하나이기에 index를 0으로 해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Task {
for try await line in fileHandle!.bytes {
print(line)
}
}
/*
74
111
104
110
10
77
97
114
121
10
10
*/
각 라인별 바이트가 나온다.
2. URL
물론 파일도 URL을 통해서 읽을 수가 있다.
1
2
3
4
5
6
7
8
9
10
11
Task {
let url = URL(fileURLWithPath: paths[0])
for try await line in url.lines {
print(line)
}
}
/*
John
Mary
*/
한줄씩 읽는다.
3. URLSession
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
1
2
3
4
5
6
7
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 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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를 하나 만들어 준다.
1
var priceHandler: (Double) -> Void = { _ in }
initializing을 하기 위해 위와 같이 만들어 준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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을 사용해서 만들어본다.
1
AsyncStream(Double.self) { continuation in
이렇게 closure형태로 쓰는데 괄호안에는 Return Type을 작성해준다.
그리고 하나 더 특이점이라면 continuation뒤에 yield를 사용해준다.
대기 중인 작업을 중단 지점에서 주어진 결과의 성공 값을 반환하며 정상적으로 재개시킨다.
즉, 이전 작업에서 성공했던 값을 반환하면서 다음 값을 기다리는 상태로 전환한다. 라고 생각하면 될듯.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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를 달아주었다.
1
2
3
4
5
6
7
8
9
10
11
12
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
이런식으로 결과가 나온다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.