์ด๋ชจ์ ๋ชจ/Swift
TaskCounter๋ก ๋ณ๋ ฌ ์์ ์๋ฃ ๊ณ์ ํ์ ํ๊ธฐ
ARpple
2023. 12. 13. 18:10
๐ก ์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ํ๋ฒ์ ๊ฐ์ ธ์์ผํ๋ ์์ ์ด ์์๋ค. ์ด๋ฏธ์ง๋ค์ ๊ฐ์ ธ์ค๋ Task๋ฅผ ๋น๋๊ธฐ๋ก ๊ฐ์ ธ์ค๋ ์์ ์ TaskGroup์ผ๋ก ์งํํ๋ค. ์ด๋ฏธ์ง๋ค์ ๊ฐ์ ธ์ค๋ ๋ชจ๋ ์์ ์๋ฃ ํ, ๋ทฐ์ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ณ ๊ธฐ๋ค๋ฆฌ๋ ๊ณผ์ ์์ Progress๋ฅผ ๋ณด์ฌ์ฃผ๋ ค ํ๋ค. ๊ฐ๊ฐ์ ์์ ์ด ์๋ฃ๋ ๊ณ์๋ฅผ ์ถ์ ํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ๊ณ ์นด์ดํฐ๋ฅผ ์ง์ ๋ง๋ค์ด ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ์์ ๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์ฌ์ฉํ ์ ์๋ Task(Group)Counter๋ฅผ ๋ง๋ค์๋ค.
์ฌ์ฉ ๊ธฐ์
- Actor → ํ์, TaskCounter๋ actor ์ธ์คํด์ค
- Combine → RxSwift๋ก ๊ตฌ์ฑํด๋ ์๊ด ์์ ๊ฒ ๊ฐ๋ค.
- Concurrency
๊ตฌํ ๋งค์ปค๋์ฆ
์ ์ฅ ํ๋กํผํฐ
- count: ์์ ์๋ฃํ ๊ณ์๋ฅผ ์นด์ดํธ
- maxCount: ๋ณ๋ ฌ ์ฒ๋ฆฌํ ์์ ์ ๊ณ์
- completed: ๋ชจ๋ ์์
์ด ์๋ฃ ๋์๋์ง ์๋ ค์ฃผ๋
PassthroughSubject
→ rxSwift์ PublishSubject
์นด์ดํ ๊ด๋ จ ๋ฉ์๋) private level
- increment
- reset
- changeMax
- failed()
Task ์ฒ๋ฆฌ ๊ด๋ จ ๋ฉ์๋
- progress: ์์
์๋ฃ ๊ณ์๊ฐ ์ฌ๋ผ๊ฐ๋ฉด ๋ณด๋ด๋
Publisher
→ rxSwift์ Observer - run: ์ค์ ์์ ํ ๋ฐ์ดํฐ ๊ทธ๋ฃน๊ณผ ๊ฐ๊ฐ์ ๊ทธ๋ฃน์ ์คํํ ์์ ์ ์ ๋ ฅํ๋ async ๋ฉ์๋
์ ์ฒด ์ฝ๋
import UIKit
import Combine
actor TaskCounter{
@Published private(set) var count = 0
@Published private(set) var maxCount: Int = 0
private(set) var completed = PassthroughSubject<Bool,Never>()
private var subscription = Set<AnyCancellable>()
func changeMax(_ max:Int){ self.maxCount = max }
private func increment(){
count += 1
if maxCount == count{
count = 0
completed.send(true)
}
}
private func reset(){ count = 0 }
private func failed(){ completed.send(false) }
var progress: AnyPublisher<(Int,Int),Never>{
$count.combineLatest($maxCount).eraseToAnyPublisher()
}
}
extension TaskCounter{
func run<T>(_ results: [T],action:@escaping ((T) async throws ->Void)) async throws{
subscription.removeAll()
self.changeMax(results.count)
self.reset()
try await withThrowingTaskGroup(of: Void.self) { group in
for result in results{
group.addTask {
do{
try await action(result)
await self.increment()
}catch{
await self.failed()
}
}
}
self.completed.sink(receiveValue: {[group] val in
if !val{ group.cancelAll() }
}).store(in: &subscription)
try await group.waitForAll()
}
}
}
โ ๋ณ๋ ฌ๋ก ์งํํ๋ ์์ ์์ Return ํ๋ ๊ฐ์ด ์กด์ฌํ๋ค๋ฉด return ๊ฐ์ ํ์ ๊ณ์์ ๋ง๊ฒ ์ ๋ค๋ฆญ ํ์ ์ ์ถ๊ฐํ run ๋ฉ์๋๋ฅผ ์์ฑํด์ ์ฒ๋ฆฌํ ์ ์์ ๊ฒ์ด๋ค.