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

Intro

Kingfisher ์ฝ”๋“œ๋ฅผ ๋ณด๊ธฐ ์ „์—, ๋จผ์ € ๋จธ๋ฆฟ์† ๊ฐœ๋…์„ ์ •๋ฆฌํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

์ด๋ฏธ์ง€ ๋กœ๋”ฉ์€ ๊ฒ‰์œผ๋กœ๋Š” ๋‹จ์ˆœํ•˜๋‹ค.

  • ๋‚ด๋ ค๋ฐ›๊ณ (Network)
  • ํ•ด์„ํ•˜๊ณ (Decode)
  • ๋ณด์—ฌ์ค€๋‹ค(Display)

๊ทธ๋Ÿฐ๋ฐ ์•ฑ์ด ๋А๋ ค์ง€๋Š” ์ˆœ๊ฐ„์€ ๊ฑฐ์˜ ํ•ญ์ƒ ์—ฌ๊ธฐ์„œ ์‹œ์ž‘ํ•œ๋‹ค.

  • ๋„คํŠธ์›Œํฌ๊ฐ€ ํ”๋“ค๋ฆฌ๊ฑฐ๋‚˜
  • ๋””์ฝ”๋”ฉ์ด ๋ˆ„์ ๋˜๊ฑฐ๋‚˜
  • ํ‘œ์‹œ ํƒ€์ด๋ฐ(UI)์ด ๋ฐ€๋ฆฌ๊ฑฐ๋‚˜

๊ทธ๋ž˜์„œ ์ด๋ฏธ์ง€ ์บ์‹œ๋Š” “ํŽธ์˜ ๊ธฐ๋Šฅ”์ด ์•„๋‹ˆ๋ผ, ์‹ค๋ฌด์—์„œ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ •์„ฑ์„ ์ง€ํƒฑํ•˜๋Š” ์„ค๊ณ„๊ฐ€ ๋œ๋‹ค.


1. ์ด๋ฏธ์ง€ ๋กœ๋”ฉ์˜ ๋น„์šฉ ๋ชจ๋ธ

์ด๋ฏธ์ง€๋Š” ๊ฒฐ๊ตญ ์ด ์ˆœ์„œ๋กœ ๋ˆ์„ ์“ด๋‹ค.

  • Network: ์™ธ๋ถ€ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋ณ€๋™์ด ํฌ๋‹ค.
  • Decode: ๊ณ ์ •๋น„์— ๊ฐ€๊น๊ณ , ์ƒ๊ฐ๋ณด๋‹ค ๋น„์‹ธ๋‹ค.
  • Display: UI ํƒ€์ด๋ฐ(์Šคํฌ๋กค, ๋ฆฌ์ŠคํŠธ)๊ณผ ๋งž๋ฌผ๋ฆฌ๋ฉด ์ฒด๊ฐ์ด ์ปค์ง„๋‹ค.

๊ฒฐ๊ตญ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋„คํŠธ์›Œํฌ๋งŒ ์ค„์ธ๋‹ค๊ณ  ๋์ด ์•„๋‹ˆ๋‹ค.
๋””์ฝ”๋”ฉ/ํ‘œ์‹œ ๋น„์šฉ๊นŒ์ง€ ๊ฐ™์ด ์ค„์—ฌ์•ผ “์ง„์งœ ๋น ๋ฅธ ํ”„๋กœ์„ธ์Šค”๊ฐ€ ๋œ๋‹ค.

1-1. ๊ทธ๋ž˜์„œ ์บ์‹œ(Cache)๋ฅผ ๋„์ž…ํ•œ๋‹ค

๋น„์šฉ์ด ํฐ ์ž‘์—…์„ ๋งค๋ฒˆ ๋ฐ˜๋ณตํ•˜๋ฉด, ์•ฑ์€ ๋А๋ ค์งˆ ์ˆ˜๋ฐ–์— ์—†๋‹ค.
๊ทธ๋ž˜์„œ ์ด๋ฏธ์ง€ ๋กœ๋”ฉ์—์„œ๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์บ์‹œ(cache) ๋ผ๋Š” ๊ฐœ๋…์ด ๋“ฑ์žฅํ•œ๋‹ค.

- ์บ์‹œ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์บ์‹œ๋Š” ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋น„์‹ผ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด๋‘๊ณ , ๋‹ค์Œ์— ๊ฐ™์€ ์š”์ฒญ์ด ์˜ค๋ฉด ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ.

 

์ด๋ฏธ์ง€ ๋กœ๋”ฉ์—์„œ “๋น„์‹ผ ์ž‘์—…”์€ ๋ณดํ†ต ์ด ๋‘ ๊ฐ€์ง€๋‹ค.

  • ๋„คํŠธ์›Œํฌ ๋‹ค์šด๋กœ๋“œ(์ง€์—ฐ/๋ณ€๋™)
  • ๋””์ฝ”๋”ฉ(๊ณ ์ •๋น„/๋ˆ„์ )

์บ์‹œ๊ฐ€ ์žˆ์œผ๋ฉด, ํ•œ ๋ฒˆ์˜ ๋‹ค์šด๋กœ๋“œ/๋””์ฝ”๋”ฉ ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฉด์„œ
“๊ฐ™์€ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์น˜๋ฅด๋Š” ์ด ๋น„์šฉ”์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์บ์‹œ๋Š” ๊ณต์งœ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์บ์‹œ๋Š” ๊ณต๊ฐ„(๋ฉ”๋ชจ๋ฆฌ/๋””์Šคํฌ) ์„ ์จ์„œ ์‹œ๊ฐ„์„ ์‚ฌ๋Š” ๊ตฌ์กฐ๋‹ค.


์ฆ‰, ์บ์‹œ๋ฅผ ๋„์ž…ํ•˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์ •์ฑ…๊ณผ ๋™์‹œ์„ฑ์ด ๋”ฐ๋ผ์˜จ๋‹ค.


2. 2๋‹จ ์บ์‹œ: Memory → Disk → Network

์ด๋ฏธ์ง€ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, ์บ์‹ฑ ํ๋ฆ„์€ ๊ฑฐ์˜ ์ด๋ ‡๊ฒŒ ํ๋ฅธ๋‹ค.

์š”์ฒญ
  → ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ํ™•์ธ (hit๋ฉด ์ฆ‰์‹œ ๋ฐ˜ํ™˜)
  → miss๋ฉด ๋””์Šคํฌ ์บ์‹œ ํ™•์ธ (hit๋ฉด ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ๋ฐ˜ํ™˜)
  → miss๋ฉด ๋„คํŠธ์›Œํฌ ๋‹ค์šด๋กœ๋“œ
      → ๋””์ฝ”๋”ฉ
      → ๋ฉ”๋ชจ๋ฆฌ + ๋””์Šคํฌ ์ €์žฅ
      → ๋ฐ˜ํ™˜

 

์ด ๊ตฌ์กฐ์˜ ํ•ต์‹ฌ์€ “์†๋„”๋งŒ์ด ์•„๋‹ˆ๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ๋Š” ๊ฐ€์žฅ ๋น ๋ฅด๋‹ค
  • ๋””์Šคํฌ ์บ์‹œ๋Š” ๊ฐ€์žฅ ์˜ค๋ž˜ ์‚ฐ๋‹ค
  • ๋„คํŠธ์›Œํฌ๋Š” ๊ฐ€์žฅ ๋ถˆ์•ˆ์ •ํ•˜๋‹ค

์ฆ‰, 2๋‹จ ์บ์‹œ๋Š” ์†๋„ / ์ง€์†์„ฑ / ๋ณต๊ตฌ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๊ฐ€์ ธ๊ฐ€๋Š” ์„ ํƒ์ด๋‹ค.


3. Memory vs Disk

๋‘˜ ๋‹ค ์บ์‹œ์ง€๋งŒ, ์ €์žฅ ํ˜•ํƒœ๊ฐ€ ๋‹ค๋ฅด๋‹ค.

- ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ: ๊ฐ์ฒด(์ธ์Šคํ„ด์Šค) ๊ทธ๋Œ€๋กœ

๋ฐ”๋กœ ๊บผ๋‚ด์„œ ์“ฐ๋Š” ํ˜•ํƒœ(์˜ˆ: UIImage)๋กœ ์ €์žฅํ•œ๋‹ค.
์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ hit = ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ์— ๊ฐ€๊น๋‹ค.

- ๋””์Šคํฌ ์บ์‹œ: ์ง๋ ฌํ™”๋œ Data/bytes

ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋ ค๋ฉด UIImage → Data๊ฐ€ ํ•„์š”ํ•˜๊ณ ,
๋‹ค์‹œ ์ฝ์œผ๋ฉด Data → UIImage๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

let data = image.pngData()!
try data.write(to: fileURL)

let loaded = try Data(contentsOf: fileURL)
let image = UIImage(data: loaded)

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํฌ์ธํŠธ๋Š”

Disk hit์€ Network miss์ผ ๋ฟ, “๋น„์šฉ 0”์ด ์•„๋‹ˆ๋‹ค.
(์ฝ๊ธฐ I/O + Data → Image ๋ณ€ํ™˜ ๋น„์šฉ์€ ๋‚จ๋Š”๋‹ค)

 


4. Decoding vs Serialization

์ด ๋‘˜์„ ์„ž์–ด ๋งํ•˜๋ฉด ์บ์‹œ ์„ค๊ณ„๊ฐ€ ํ๋ ค์ง„๋‹ค.

  • ์ง๋ ฌํ™”(Serialization): UIImage → Data
    ์ €์žฅ/์ „์†ก ๊ฐ€๋Šฅํ•œ ๋ฐ”์ดํŠธ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
  • ๋””์ฝ”๋”ฉ(Decoding): Data → ๋ Œ๋”๋ง ๊ฐ€๋Šฅํ•œ ์ด๋ฏธ์ง€ ํ‘œํ˜„
    ํ™”๋ฉด์— ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋„๋ก ๋‚ด๋ถ€ ํ‘œํ˜„(ํ”ฝ์…€ ์ค€๋น„ ํฌํ•จ)์œผ๋กœ ์ค€๋น„

๋””์Šคํฌ ์บ์‹œ๋Š” ๋ณดํ†ต Data๋ฅผ ์ €์žฅํ•œ๋‹ค.
๊ทธ๋ž˜์„œ ๋””์Šคํฌ์—์„œ ๊บผ๋‚ด๋Š” ์ˆœ๊ฐ„์—๋„, ๋‹ค์‹œ ๋น„์šฉ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ
  • ๋””์ฝ”๋”ฉ ๋น„์šฉ(๋˜๋Š” ๊ทธ์— ์ค€ํ•˜๋Š” ์ค€๋น„ ๋น„์šฉ)

์ฆ‰,

  • Disk hit = “๋„คํŠธ์›Œํฌ ๋น„์šฉ์„ ํ”ผํ–ˆ๋‹ค”
  • Disk hit ≠ “๋””์ฝ”๋”ฉ ๋น„์šฉ์ด ์‚ฌ๋ผ์กŒ๋‹ค”

5. ์บ์‹œ๋Š” ์ •์ฑ…์ด๋‹ค

์บ์‹œ๋Š” ๋ฌดํ•œํ•˜์ง€ ์•Š๋‹ค.
๊ทธ๋ž˜์„œ ์ €์žฅ์„ ์‹œ์ž‘ํ•˜๋ฉด ๊ณง๋ฐ”๋กœ ์ •์ฑ…์ด ํ•„์š”ํ•ด์ง„๋‹ค.

  • Eviction(๊ต์ฒด): ๊ณต๊ฐ„์ด ๋ถ€์กฑํ•  ๋•Œ ๋ฌด์—‡์„ ๋ฒ„๋ฆด์ง€
  • Expiration(๋งŒ๋ฃŒ): ์–ธ์ œ๊นŒ์ง€ ์œ ํšจํ•œ์ง€
  • Cleanup(์ •๋ฆฌ): ์–ธ์ œ ์‹ค์ œ๋กœ ์‚ญ์ œํ• ์ง€

์—ฌ๊ธฐ์„œ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์ƒ๊ธด๋‹ค.

  • ์ •ํ™•ํ•˜๊ฒŒ ๊ด€๋ฆฌํ• ์ˆ˜๋ก → ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ/์—ฐ์‚ฐ/๋™๊ธฐํ™” ๋น„์šฉ์ด ์˜ค๋ฅธ๋‹ค
  • ๋‹จ์ˆœํ•˜๊ฒŒ ํ• ์ˆ˜๋ก → ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ/์ •ํ•ฉ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค

6.  iOS์—์„œ ์บ์‹œ๊ฐ€ ‘์ €์žฅ์†Œ’๊ฐ€ ์•„๋‹Œ ์ด์œ 

์—ฌ๊ธฐ๊นŒ์ง€ ์˜ค๋ฉด ์ด๋Ÿฐ ์ƒ๊ฐ์ด ๋“ ๋‹ค.

“์บ์‹œ๋Š” ๊ทธ๋ƒฅ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๋ฉด ๋˜๋Š” ๊ฑฐ ์•„๋ƒ?”

ํ•˜์ง€๋งŒ iOS์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•œ์ •๋˜์–ด ์žˆ๊ณ , OS๊ฐ€ ๊ฐ•ํ•˜๊ฒŒ ๊ฐœ์ž…ํ•œ๋‹ค.


์ฆ‰, ์บ์‹œ๋Š” “๋‚ด๊ฐ€ ์žก๊ณ  ์žˆ์œผ๋ฉด ์œ ์ง€๋˜๋Š” ์ €์žฅ์†Œ” ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์บ์‹œ์˜ ์ „์ œ๋Š” ๋ณดํ†ต ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

์žˆ์œผ๋ฉด ๋น ๋ฅด๋‹ค. ํ•˜์ง€๋งŒ ์—†์–ด์ ธ๋„ ์•ˆ์ „ํ•ด์•ผ ํ•œ๋‹ค. (best-effort)

 

๊ทธ๋ž˜์„œ Apple์€ ์บ์‹œ๋ฅผ “์ •ํ™•ํ•œ ์ €์žฅ์†Œ”๋กœ ๋งŒ๋“ค๊ธฐ๋ณด๋‹ค๋Š”,
์บ์‹œ์— ๋งž๋Š” ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๊ทธ ๋Œ€ํ‘œ๊ฐ€ NSCache๋‹ค.


7.  NSCache

NSCache๋Š” ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ์บ์‹œ ์šฉ๋„๋กœ ์„ค๊ณ„๋œ ์ปจํ…Œ์ด๋„ˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ ๊ด€์ ์€ ํ•˜๋‚˜๋งŒ ๊ธฐ์–ตํ•˜๋ฉด ๋œ๋‹ค.

NSCache๋Š” ‘์ •ํ™•ํ•œ ์ €์žฅ์†Œ’๊ฐ€ ์•„๋‹ˆ๋ผ, ‘๋ฒ„๋ ค์ ธ๋„ ์•ˆ์ „ํ•œ ์บ์‹œ’์— ๊ฐ€๊น๋‹ค.


์ฆ‰, ์บ์‹œ miss๋ฅผ ๊ธฐ๋ณธ ์ „์ œ๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  NSCache๊ฐ€ “์บ์‹œ ์ปจํ…Œ์ด๋„ˆ”๋กœ ์ž์ฃผ ์“ฐ์ด๋Š” ์ด์œ ๋Š” ๋ณดํ†ต ์•„๋ž˜ ์„ฑ์งˆ ๋•Œ๋ฌธ์ด๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์บ์‹œ๊ฐ€ ์ž๋™์œผ๋กœ ๋น„์›Œ์งˆ ์ˆ˜ ์žˆ๋Š”(eviction) ๋ฐฉํ–ฅ์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ๊ณ 
  • ๊ธฐ๋ณธ์ ์ธ set/get/remove๋Š” ๊ฐ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋‹จ์œ„์—์„œ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค. (Thread Safe)
  • ํ‚ค๋ฅผ copyํ•˜์ง€ ์•Š๋Š”๋‹ค

์ด์ œ ์ด “ํ‚ค๋ฅผ copyํ•˜์ง€ ์•Š๋Š”๋‹ค”๊ฐ€ ์™œ ์ค‘์š”ํ•œ์ง€ ๋ณด์ž.

7-1. (Deep) NSCache๋Š” key๋ฅผ copyํ•˜์ง€ ์•Š๊ณ  retain ํ•œ๋‹ค

NSCache๋Š” NSMutableDictionary์™€ ๋‹ค๋ฅด๊ฒŒ, ํ‚ค๋ฅผ copyํ•˜์ง€ ์•Š๋Š”๋‹ค.


์ฆ‰, ๋„ฃ์€ ํ‚ค ๊ฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ retain(์ฐธ์กฐ ์œ ์ง€) ํ•œ๋‹ค.

์ด๊ฒŒ ์™œ ์ค‘์š”ํ• ๊นŒ?

  • ํ‚ค๊ฐ€ mutable(๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š”) ์ฐธ์กฐ ํƒ€์ž…์ด๊ณ 
  • ํ‚ค์˜ ๋™๋“ฑ์„ฑ/ํ•ด์‹œ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด
  • ์บ์‹œ hit/miss๊ฐ€ ๊ผฌ์ผ ์ˆ˜ ์žˆ๋‹ค

๊ทธ๋ž˜์„œ ์‹ค์ œ NSCache๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋ณดํ†ต ํ‚ค๋กœ ๋ถˆ๋ณ€(immutable) ๊ฐ์ฒด๋ฅผ ์“ด๋‹ค.
(๋Œ€ํ‘œ์ ์œผ๋กœ NSString)


8. ํ‚ค๋Š” ์™œ ๋ณดํ†ต NSString์ธ๊ฐ€

์—ฌ๊ธฐ์„œ Swift ์‚ฌ์šฉ์ž๋“ค์ด ํ•ญ์ƒ ๋งˆ์ฃผ์น˜๋Š” ์ œ์•ฝ์ด ํ•˜๋‚˜ ๋‚˜์˜จ๋‹ค.

NSCache<KeyType, ObjectType>์˜ KeyType/ObjectType์€ ํด๋ž˜์Šค ํƒ€์ž…(AnyObject) ์ด์–ด์•ผ ํ•œ๋‹ค.

 

Swift์˜ String์€ ๊ฐ’ ํƒ€์ž…(struct) ์ด๋‹ค.
๊ทธ๋ž˜์„œ String์„ NSCache์˜ key ํƒ€์ž…์œผ๋กœ ์ง์ ‘ ์“ธ ์ˆ˜ ์—†๊ณ  ๋ณดํ†ต ์ด๋ ‡๊ฒŒ ๋งŽ์ด ์“ด๋‹ค.

let cache = NSCache<NSString, UIImage>()
cache.setObject(image, forKey: key as NSString)

 

์ •๋ฆฌํ•˜๋ฉด,

  • NSCache๋Š” ํ‚ค๋ฅผ copyํ•˜์ง€ ์•Š๊ณ  retain ํ•œ๋‹ค
    → ํ‚ค๋Š” “๋ถˆ๋ณ€”์ด ์•ˆ์ „ํ•˜๋‹ค
  • NSCache๋Š” ํ‚ค ํƒ€์ž…์ด AnyObject(ํด๋ž˜์Šค) ์—ฌ์•ผ ํ•œ๋‹ค
    → Swift String์€ ์ง์ ‘ ๋ชป ์“ฐ๊ณ  NSString์œผ๋กœ ๋ธŒ๋ฆฌ์ง•ํ•œ๋‹ค

๋‹ค์‹œ ๋งํ•ด, NSCache๋Š” ์ œ๋„ค๋ฆญ ์ œ์•ฝ์ด AnyObject๋ผ์„œ Swift ๊ฐ’ ํƒ€์ž…์€ ๊ทธ๋Œ€๋กœ Key/Object๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
๊ทธ๋ž˜์„œ Key๋Š” NSString์ฒ˜๋Ÿผ ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ๋ธŒ๋ฆฌ์ง•/๊ตฌ์„ฑํ•ด์„œ ์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.


9. Thread-safe ≠ Atomic

NSCache๋Š” ๊ธฐ๋ณธ API๊ฐ€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค.


๊ทธ๋Ÿผ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ๋์ผ๊นŒ?

์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ‘์›์ž์„ฑ(atomicity)’ ๋ฌธ์ œ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค.

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ์ด๊ฑฐ๋‹ค.

  • NSCache๊ฐ€ ๋ณด์žฅํ•˜๋Š” ๊ฑด ๋ณดํ†ต ๋‹จ์ผ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋‹จ์œ„์˜ ์•ˆ์ „์„ฑ
  • ์‹ค๋ฌด์—์„œ ๊นจ์ง€๋Š” ๊ฑด ๋ณตํ•ฉ ๋กœ์ง ๋‹จ์œ„(์›์ž์„ฑ)

9-1. check-then-act๊ฐ€ ๊นจ์ง€๋Š” ์ด์œ  (์ค‘๋ณต work)

if cache.object(forKey: k) == nil {          // check
    cache.setObject(makeValue(), forKey: k)  // act
}

๋งŒ์•ฝ ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— check๋ฅผ ์ง„ํ–‰ํ•ด์„œ ๋‘˜ ๋‹ค “nil”์ด๋ผ๊ณ  ํŒ๋‹จํ•˜๋ฉด,

  • Thread A๋„ makeValue()๋ฅผ ์‹คํ–‰ํ•˜๊ณ 
  • Thread B๋„ makeValue()๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

์ฆ‰, “ํ•œ ๋ฒˆ๋งŒ ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜ ๊ฐ’ ์ƒ์„ฑ ์ž‘์—…”์ด ์ค‘๋ณต์œผ๋กœ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‘˜ ๋‹ค setObject๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด,
์บ์‹œ ์ž…์žฅ์—์„œ๋Š” ๊ฐ™์€ key์— ๋Œ€ํ•ด ๋งˆ์ง€๋ง‰์— set๋œ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์จ์งˆ ๋ฟ์ด์ง€๋งŒ,

์ด๋ฏธ ๋น„์‹ผ ์ž‘์—…(๋‹ค์šด๋กœ๋“œ/๋””์ฝ”๋”ฉ/๊ฐ€๊ณต)์€ ๋‘ ๋ฒˆ ์ˆ˜ํ–‰๋œ ๋’ค๋‹ค.

 

์ฆ‰, ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ผ๋ฉด “ํ•œ ๋ฒˆ๋งŒ ๋งŒ๋“ค๊ธฐ” ๊ฐ™์€ ์˜๋„(์›์ž์„ฑ) ๊ฐ€ ๊นจ์ง€๊ณ ,
๊ฒฐ๊ณผ๋ณด๋‹ค ๋” ํฐ ๋ฌธ์ œ๋กœ ์ค‘๋ณต ๋น„์šฉ์ด ๋ฐœ์ƒํ•œ๋‹ค.

9-2. NSCache + ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ถ™์ด๋Š” ์ˆœ๊ฐ„, ์›์ž์„ฑ์ด ํ•„์š”ํ•ด์ง„๋‹ค

์‹ค์ „ ์บ์‹œ๋Š” NSCache๋งŒ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

  • ๋งŒ๋ฃŒ ์‹œ๊ฐ„
  • lastAccessed
  • keys ๋ชฉ๋ก
  • cost/size ์ถ”์ 

์ด๋Ÿฐ ์ƒํƒœ ์ •๋ณด๋ฅผ ๊ฐ–๋Š” ์ˆœ๊ฐ„ ์บ์‹œ๋Š”
“์บ์‹œ + ์ƒํƒœ(๋ฉ”ํƒ€๋ฐ์ดํ„ฐ)” ๋ฅผ ๋™์‹œ์— ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

๊ทธ๋•Œ๋ถ€ํ„ฐ๋Š” ๋‹จ์ˆœํžˆ thread-safe๊ฐ€ ์•„๋‹ˆ๋ผ,
NSCache ์—…๋ฐ์ดํŠธ์™€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ๋ฌถ๋Š” ์„ค๊ณ„(์›์ž์„ฑ) ๊ฐ€ ํ•„์š”ํ•ด์ง„๋‹ค.


10. ๋งŒ๋ฃŒ(Expiration)์™€ ์ •๋ฆฌ(Cleanup)

๋งŒ๋ฃŒ๋Š” ๋ณดํ†ต ๋‘ ๊ฐ€์ง€ ๊ธฐ์ค€์œผ๋กœ ์žก๋Š”๋‹ค.

  • TTL(Time To Live): ์ƒ์„ฑ ์‹œ์  ๊ธฐ์ค€
  • lastAccessed: ๋งˆ์ง€๋ง‰ ์ ‘๊ทผ ์‹œ์  ๊ธฐ์ค€

๊ทธ๋ฆฌ๊ณ  ์‚ญ์ œ(์ •๋ฆฌ) ํƒ€์ด๋ฐ์€ ๋ณดํ†ต 3๊ฐ€์ง€๋กœ ๋‚˜๋‰œ๋‹ค.

  • ์ ‘๊ทผ ์‹œ ์ •๋ฆฌ: ์ฝ์„ ๋•Œ ๋งŒ๋ฃŒ๋ฉด ์‚ญ์ œ
  • ์ฃผ๊ธฐ์  ์ •๋ฆฌ: ๋ฐฑ๊ทธ๋ผ์šด๋“œ/ํƒ€์ด๋จธ ๊ธฐ๋ฐ˜
  • ํ˜ผํ•ฉ: ๋‘˜์„ ์„ž์–ด์„œ ์šด์˜

์—ฌ๊ธฐ์„œ๋„ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์žˆ๋‹ค.

  • ์ ‘๊ทผ ์‹œ ์ •๋ฆฌ: ๋‹จ์ˆœํ•˜์ง€๋งŒ “์ ‘๊ทผ ์ˆœ๊ฐ„”์ด ๋ฌด๊ฑฐ์›Œ์งˆ ์ˆ˜ ์žˆ์Œ
  • ์ฃผ๊ธฐ์  ์ •๋ฆฌ: ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐํ•˜์ง€๋งŒ ์Šค์ผ€์ค„๋ง/๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•จ

11. Jetsam: ์บ์‹œ miss๊ฐ€ ๊ธฐ๋ณธ์ธ ์ด์œ 

iOS์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋Š” “๋‚ด๊ฐ€ ์žก๋Š”๋‹ค๊ณ  ์œ ์ง€๋˜๋Š” ์ž์›”์ด ์•„๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ•์ด ์˜ค๋ฉด,

  • ์บ์‹œ๋Š” ๋น„์›Œ์งˆ ์ˆ˜ ์žˆ๊ณ 
  • ์‹ฌํ•˜๋ฉด ์•ฑ์ด ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ๋‹ค (Jetsam)

๊ทธ๋ž˜์„œ ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ์˜ ์ „์ œ๋Š” ์ด๋ ‡๊ฒŒ ๋ฐ”๋€๋‹ค.

“์บ์‹œ hit์„ ๊ธฐ๋Œ€ํ•˜๋˜, miss๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์„ค๊ณ„ํ•œ๋‹ค.”

 

๊ทธ๋ฆฌ๊ณ  ๋””์Šคํฌ ์บ์‹œ์˜ ์˜๋ฏธ๋Š” ์—ฌ๊ธฐ์„œ ์ปค์ง„๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ€๋„
  • ์•ฑ์ด ์žฌ์‹œ์ž‘ํ•ด๋„
  • ๋ณต๊ตฌ ๋น„์šฉ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ

๋งˆ๋ฌด๋ฆฌ

์ด๋ฏธ์ง€ ์บ์‹œ๋Š” ๋‹จ์ˆœํžˆ “์ €์žฅํ•ด๋‘๊ณ  ์žฌ์‚ฌ์šฉ”์—์„œ ๋๋‚˜์ง€ ์•Š๋Š”๋‹ค.


๋„คํŠธ์›Œํฌ/๋””์ฝ”๋”ฉ/ํ‘œ์‹œ๋ผ๋Š” ๋น„์šฉ ๋ชจ๋ธ ์œ„์—์„œ,

2๋‹จ ๊ตฌ์กฐ(Memory/Disk) ์™€ ์ •์ฑ…(Eviction/Expiration/Cleanup) ์„ ์„ค๊ณ„ํ•ด์•ผ ํ•˜๊ณ ,

๊ทธ ๊ณผ์ •์—์„œ ๋™์‹œ์„ฑ(์›์ž์„ฑ)๊ณผ iOS์˜ ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ•(Jetsam) ์ด๋ผ๋Š” ํ˜„์‹ค์„ ๊ฐ™์ด ๋Œ์–ด์•ˆ๊ฒŒ ๋œ๋‹ค.

 

์ด๋ฒˆ ์ •๋ฆฌ์˜ ๊ฒฐ๋ก ์€ ํ•˜๋‚˜๋‹ค.

์บ์‹œ๋Š” ‘์ •ํ™•ํ•œ ์ €์žฅ์†Œ’๊ฐ€ ์•„๋‹ˆ๋ผ, ‘๊นจ์ ธ๋„ ์•ˆ์ „ํ•ด์•ผ ํ•˜๋Š” ์ตœ์ ํ™” ๋ ˆ์ด์–ด’๋‹ค.


๊ทธ๋ž˜์„œ ์บ์‹œ๋ฅผ ์“ธ ๋•Œ๋Š” ํ•ญ์ƒ ์ด๋ ‡๊ฒŒ ์งˆ๋ฌธํ•ด์•ผ ํ•œ๋‹ค.

  • ์ง€๊ธˆ ์ค„์ด๋ ค๋Š” ๋น„์šฉ์€ ๋ฌด์—‡์ธ๊ฐ€? (Network / Decode / Display)
  • ์ด ์ตœ์ ํ™”๋Š” ์–ด๋–ค ๋น„์šฉ์„ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๊ฐ€? (๊ณต๊ฐ„ / ์ •์ฑ… / ๋™๊ธฐํ™”)
  • ๊ทธ๋ฆฌ๊ณ  OS๊ฐ€ ๊ฐœ์ž…ํ–ˆ์„ ๋•Œ๋„ ์•ˆ์ „ํ•œ๊ฐ€? (eviction / Jetsam)

์ด์ œ ๋‹ค์Œ ๊ธ€์—์„œ๋Š” Kingfisher๊ฐ€ ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ๊ฐœ๋…, ๋ฌธ์ œ ์ƒํ™ฉ ๋“ฑ์„ ๊ณ ๋ คํ•˜๊ณ  ์–ด๋–ค ์‹์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€์— ๋Œ€ํ•ด์„œ ํ•™์Šตํ•˜๋ฉด ๋œ๋‹ค.
์ด ์งˆ๋ฌธ๋“ค์ด ์‹ค์ œ ๊ตฌํ˜„์—์„œ ์–ด๋–ค ํ˜•ํƒœ๋กœ ๋“œ๋Ÿฌ๋‚˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.