ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

 

๋ฐฐ๊ฒฝ

 

๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์ด์ง• ๊ตฌ์กฐ๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ณ ,

๊ฐ ๋ฐ์ดํ„ฐ res๊ฐ’์— ๋Œ€ํ•ด ๋ณ„๋„๋กœ ๋น„๋™๊ธฐ ์ƒ์„ธ ์ •๋ณด API์„ ์ถ”๊ฐ€๋กœ ์š”์ฒญํ•˜๊ณ 

ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์—ฌ๋Ÿฌ api๊ฐ€ ๋™์‹œ์— ํ˜ธ์ถœ๋˜์–ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

 

 

 

๋ฌธ์ œ ์›์ธ๊ณผ ํ•ด๊ฒฐ

 

 

์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

func loadPage() async {
    let page = try await api.fetchPage()
    for item in page.items {
        let detail = try await api.fetchDetail(id: item.id)
        messages.append(detail)
    }
    listRelay.accept(messages)
}

 

 

์ด๋ ‡๊ฒŒ ํ˜ธ์ถœํ•˜์˜€์„๋•Œ์˜ ๋ฌธ์ œ์ ์€

์š”์ฒญ์ด ์ˆœ์„œ๋Œ€๋กœ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ๋Œ€๊ธฐ ์‹œ๊ฐ„ ๋ˆ„์  ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค

 

 

 

์šฐ์„  ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”

api ํ˜ธ์ถœ์„ ๋ณ‘๋ ฌ๋กœ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

 

 

 

 

 

๊ทธ๋ž˜์„œ

 

TaskGroup๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ๋ณ‘๋ ฌ๋กœ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์ฃผ๋„๋ก ํ•˜์˜€๊ณ ,

 

let results = try await withTaskGroup { 
    for {
        group.addTask { 
            ...
            return ..
        }
    }
}

 

 

 

 

๋ณ‘๋ ฌ๋กœ ๋ฐ›์€ ๊ฐ’๋“ค์— ๋Œ€ํ•ด ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•ด์ฃผ๊ธฐ์œ„ํ•ด

api ํ˜ธ์ถœ ์‹œ์ ์— index๋ฅผ ๋ถ€์—ฌํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

let results = try await withTaskGroup {
            for (index, item) in page.items.enumerated() {
                group.addTask {
                    let detail = try await api.fetchDetail(id: item.id)
                    return (index, detail)
                }
            }
        }
        .sorted { $0.0 < $1.0 }
        .map { $1 }

 

 

๊ทธ๋ฆฌ๊ณ  index๊ฐ’์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ

ํ˜ธ์ถœ ์ˆœ์„œ๋Œ€๋กœ ๊ฒฐ๊ณผ๊ฐ’๋“ค์„ ์ •๋ ฌํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๊ทธ๋ž˜์„œ ์ด๋Ÿฐ์‹์œผ๋กœ ์ˆ˜์ •ํ•˜์—ฌ ์ฒ˜์Œ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์ˆ˜์ •๋œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

@MainActor // model data race ๋ฐฉ์ง€
func loadAllPages() async {
    var token: String? = nil
    resetState()

    while !reachedEnd && !Task.isCancelled {
        guard !isLoading else { return }
        isLoading = true

        let page = try await api.fetchPage(token: token)

        let results = try await withTaskGroup {
            for (index, item) in page.items.enumerated() {
                group.addTask {
                    let detail = try await api.fetchDetail(id: item.id)
                    return (index, detail)
                }
            }
        }
        .sorted { $0.0 < $1.0 }
        .map { $1 }

        for message in results {
            messages.insert(message, at: 0)
        }

        listRelay.accept(messages)

        if page.hasMore {
            token = page.nextToken
        } else {
            reachedEnd = true
        }

        isLoading = false
    }
}

 

 

 

ํ•œ๋ฒˆ์— ํŠน์ • ๋‚ ์งœ์˜ ๋ชจ๋“  ๋ฉ”์„ธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด

while๋กœ ๊ณ„์† ํ˜ธ์ถœํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๊ณ ,

res ๊ฐ’์— hasMore์ด false์ผ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค

 

 

 

๊ทธ๋ฆฌ๊ณ  enumerated๋กœ ๊ฐ ์š”์ฒญ์— ์ธ๋ฑ์Šค๋ฅผ ๋ถ€์—ฌํ•ด

๋ณ‘๋ ฌ ํ˜ธ์ถœ์— ๋Œ€ํ•œ response๊ฐ’์˜ ์ˆœ์„œ๋ฅผ ์žฌ์ •๋ ฌํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค

 

 

๋งˆ๋ฌด๋ฆฌ

 

ํŽ˜์ด์ง€๋Š” ์ฐจ๋ก€๋Œ€๋กœ, ํŽ˜์ด์ง€ ์•ˆ์€ ๋™์‹œ์—, ์ •๋ ฌ์€ ์ธ๋ฑ์Šค๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ
๋น„๋™๊ธฐ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง• ๊ตฌ์กฐ๋ฅผ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค

 

 

 

 

๋Œ“๊ธ€