tags: README

๐Ÿ“š Digital Library

ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

ํ™˜๊ฒฝ๋ถ€_๋””์ง€ํ„ธ๋„์„œ๊ด€ ์†Œ์žฅ์ž๋ฃŒ ๋ชฉ๋ก์„ ๋ฐ›์•„์™€ GridView ๋กœ ํ‘œํ˜„ํ•œ ์•ฑ ์ž…๋‹ˆ๋‹ค.

๐Ÿ“‘ ๋ชฉ์ฐจ

๐Ÿ”‘ ํ•ต์‹ฌ๊ธฐ์ˆ 

  • UI ๊ตฌํ˜„
    • SwiftUI
    • NavigationLink
  • ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ
    • async-await
    • DispatchQueue
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    • LWBNetwork

๐Ÿ“ฑ ์‹คํ–‰ํ™”๋ฉด

ํ™ˆํ™”๋ฉด ์ƒ์„ธํ™”๋ฉด

๐Ÿ”ญ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

  • ๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ๊ธฐ์— ์•„ํ‚คํ…์ณ๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š๊ณ , Model ๊ณผ View ๋กœ๋งŒ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

โš™๏ธ ์ ์šฉํ•œ ๊ธฐ์ˆ 

โœ… LWBNetwork

  • ์ง์ ‘ ๋งŒ๋“  ๋„คํŠธ์›Œํ‚น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค. ์ž์ฃผ ์‚ฌ์šฉํ•˜๋˜ ๋„คํŠธ์›Œํ‚น ์ฝ”๋“œ๋ฅผ ์ถ”์ƒํ™” ํ•˜์—ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌํ™” ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • async-await ์œผ๋กœ ๋„คํŠธ์›Œํฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์–ด์žˆ์–ด, ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ๋„ async-await ์œผ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โœ… ๋‹น๊ฒจ์„œ ๋‹ค์Œ ํŽ˜์ด์ง€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

  • ๋ฐ์ดํ„ฐ 20๊ฐœ ์”ฉ ํŽ˜์ด์ง•์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ชฉ์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์Šคํฌ๋กค์ด ์Šคํฌ๋กค๋ทฐ ์ตœํ•˜๋‹จ์— ๋‹ฟ์€ ์ƒํƒœ์—์„œ, ์‚ฌ์šฉ์ž๊ฐ€ ๋” ์•„๋ž˜๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ๋‹น๊ฒผ์„ ๋•Œ๋ฅผ ์ธ์‹ํ•˜๊ธฐ ์œ„ํ•ด PreferenceKey ๋ฅผ ์ด์šฉํ•˜์—ฌ ScrollOffset ์ƒํƒœ๋ฅผ ๊ตฌ๋…ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ง€์ •ํ•œ offSet ๊ฐ’(100) ์„ ๋„˜๊ฒŒ ๋‹น๊ธฐ๋ฉด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ์„ค์ • ํ–ˆ์Šต๋‹ˆ๋‹ค.
.onPreferenceChange(ScrollOffsetKey.self) { value in
    let atBottomValue = DeviceSize.height - CGFloat(160)
    let scrollOffset = atBottomValue - value

    if scrollOffset > 100 {
        guard shouldFetchMoreBooks == false else { return }
        shouldFetchMoreBooks = true
    }
}

โœ… ToastMessage

  • ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ, ์•Œ๋ฆผ์„ ์ฃผ๊ธฐ ์œ„ํ•ด ToastMessage๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

โœ… Sticky Header

  • ์‚ฌ์šฉ์ž์—๊ฒŒ ์ต์ˆ™ํ•œ UI๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ธ๋ณด๊ธฐ์—์„œ Sticky Header๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

โœ… LightMode / DarkMode

  • ๋ผ์ดํŠธ๋ชจ๋“œ์™€ ๋‹คํฌ๋ชจ๋“œ ๋‘ ๋ชจ๋“œ์—์„œ ์ƒ‰๊ฐ์ฐจ์ด๋ฅผ ๋ณด์ด์ง€ ์•Š๋„๋ก Semantic Color๋ฅผ ์ด์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ™ˆํ™”๋ฉด ์ƒ์„ธํ™”๋ฉด

โš ๏ธ Trouble Shooting

๐Ÿ›  ์ด๋ฏธ์ง€ ํฌ๊ธฐ์˜ ๋‹ค์–‘์„ฑ

  • ์ฑ… ํ‘œ์ง€ ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๊ฒƒ์— ๋Œ€ํ•ด์„œ๋Š” PlaceholderImage ๋ฅผ ๋งŒ๋“ค์–ด ์ ์šฉ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ฑ… ํ‘œ์ง€ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์–ด๋„ ํฌ๊ธฐ๊ฐ€ ๋‹ค์–‘ํ•ด์„œ width ๊ฐ’๋งŒ ํ†ต์ผ ์‹œ์ผœ์ฃผ๊ณ  ์ตœ๋Œ€ ๋†’์ด๊ฐ’์— ๋งž์ถฐ ์…€ ๋†’์ด๋ฅผ ํ˜•์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ›  async๋ฉ”์„œ๋“œ ์‚ฌ์šฉ์‹œ data-race ๋ฌธ์ œ ๋ฐœ์ƒ

  • ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กค์„ ์ง€์ •๊ฐ’(100) ์ด์ƒ ๋‹น๊ฒผ์„ ๋•Œ, ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ์„ค์ •ํ–ˆ๋Š”๋ฐ, 100์„ ๋„˜์€ ์ˆœ๊ฐ„์ด ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐœํ–‰ ๋˜์–ด ์ˆ˜๋งŽ์€ ์š”์ฒญ์ด ๋™์‹œ์— ๋ฐœ์ƒ๋˜์–ด ๋‹ค์ŒํŽ˜์ด์ง€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ๊ฐ™์€ ํŽ˜์ด์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ค‘๋ณตํ•ด์„œ ๋ถˆ๋Ÿฌ์˜ค๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฎคํ…์Šค๋ฝ์˜ ์—ญํ• ์„ ํ•ด์ค„ Bool ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ํ•œ๋ฒˆ์˜ ๋‹น๊น€์— ํ•œ๋ฒˆ์˜ ์š”์ฒญ๋งŒ ์ผ์–ด๋‚˜๊ฒŒ ๋งŒ๋“ค๊ณ , asyncAfter ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ Bool ํƒ€์ž… ๋ณ€์ˆ˜๋Š” 1์ดˆ๋’ค์— toggle() ์ด ๋˜๋„๋ก ๋งŒ๋“ค์–ด ์ค‘๋ณต์š”์ฒญ์„ ๋ง‰์•„์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”— References