Giter Club home page Giter Club logo

til's Introduction

Sangwon Shin ๐Ÿ‘‹

Hits

who am I?

  • ๐Ÿ‘ฏ I majored in Electronic Engineering
  • ๐Ÿ“ซ Konkuk University (2015.03 ~ 2021.08)

sangwon's github stats

sangwon's github stats

til's People

Contributors

brandnew-one avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

til's Issues

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 5

HTTP Method ํ™œ์šฉ

ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ์ „์†ก

  • ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก
    • GET
  • ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก
    • POST, PUT, PATCH

(๊ฒฝํ—˜์— ๋น„์ถ”์–ด ๋ณด๋ฉด),

์ผ๋ฐ˜์ ์œผ๋กœ GET์„ ํ†ตํ•ด์„œ API ํ†ต์‹ ์„ ํ•˜๋ฉด ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ํ•„ํ„ฐ๋ง ์˜ต์…˜์„ ๋„ฃ์–ด์ฃผ๋ฉด ์ตœ์ข…์ ์ธ URI ํ˜•ํƒœ๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ๋„ฃ์–ด์ค€ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ {key - value} ์Œ์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค. (HTTP ๋ฒ„์ „์— ๋”ฐ๋ผ ๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

POST, PUT, PATCH ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋“ค์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„์— ๋ณด๋‚ด๋ ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ json์œผ๋กœ ์ธ์ฝ”๋”ฉ ์‹œ์ผœ์„œ ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ๋„ฃ์–ด์„œ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ํ•œ๋‹ค.


๋ฐ์ดํ„ฐ ์กฐํšŒ

  • ๋ฐ์ดํ„ฐ ์กฐํšŒ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ GET ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉ
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์ •์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์ด ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ๋กœ ๋‹จ์ˆœํ•˜๊ฒŒ ์กฐํšŒ ๊ฐ€๋Šฅ
  • ๋™์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•„ํ„ฐ๋ฅผ ์ ์šฉ

HTML Form ๋ฐ์ดํ„ฐ ์ „์†ก

  • GET, POST ๋ฉ”์„œ๋“œ๋งŒ ์‚ฌ์šฉ๊ฐ€๋Šฅ

์›น ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹ˆ๋ผ์„œ HTML Form ๋ฐ์ดํ„ฐ ์ „์†ก์— ๋Œ€ํ•ด์„œ ์ฒ˜์Œ ๋“ค์–ด๋ดค๋Š”๋ฐ HTML Form์— ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์— ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์ด ๋”ฐ๋กœ ์žˆ๋‹ค ์ •๋„๋กœ ์ดํ•ดํ–ˆ๋‹ค.

๊ฐ•์˜์—์„œ ํ•ด๋‹น๋‚ด์šฉ์„ ์„ค๋ช… ํ•˜๋ฉด์„œ HTML Form์—์„œ ์‚ฌ์šฉํ•˜๋Š” Content-Type์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ ์ด ๋ถ€๋ถ„์„ ํ•œ๋ฒˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž

  • application/x-www-form-urlencoded
    • form์˜ ๋‚ด์šฉ์„ ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ํ†ตํ•ด key = value ํ˜•ํƒœ๋กœ ์ „์†ก
    • ์ „์†ก ๋ฐ์ดํ„ฐ url encoding
  • multipart/form-data
    • ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ ์ „์†ก(์—…๋กœ๋“œ)
    • ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์—ฌ๋Ÿฌ ํŒŒ์ผ ํผ ์ „์†ก ๊ฐ€๋Šฅ
Untitled Untitled 1

(์ต์ˆ™ํ•˜์ฃ ..?)

Content-Type์€ HTTP ์š”์ฒญ ๋˜๋Š” ์‘๋‹ต์˜ ๋ณธ๋ฌธ(content)์˜ ๋ฏธ๋””์–ด ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ—ค๋” ํ•„๋“œ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹์„ ๋ช…์‹œํ•˜๊ณ , ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

Content-Type: media-type

**media-type**์€ MIME(Multipurpose Internet Mail Extensions) ํƒ€์ž…์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ฏธ๋””์–ด ํƒ€์ž…์„ ๋ช…์‹œํ•˜๋Š” ๋ฌธ์ž์—ด

์š”์•ฝํ•˜์ž๋ฉด

  • Contenty-Type์— ๋ช…์‹œ๋œ ๋ฐ์ดํ„ฐ ํ˜•์‹์œผ๋กœ ์„œ๋ฒ„ <-> ํด๋ผ์ด์–ธํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋‹ค.
  • Content-Type ํ—ค๋”์— ๋ช…์‹œ๋˜๋Š” ๋ฐ์ดํ„ฐ ํ˜•์‹์€ MIME ํƒ€์ž…์ด๋‹ค.

HTTP API ๋ฐ์ดํ„ฐ ์ „์†ก

  • ์•ฑ ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ์ „์†กํ•˜๋Š” ํ˜•์‹
  • ์„œ๋ฒ„ โ†’ ์„œ๋ฒ„
  • Content-Type์€ ์ผ๋ฐ˜์ ์œผ๋กœ application/json

์ง€๋‚œ ์‹œ๊ฐ„์— ์ •๋ฆฌํ–ˆ๋˜ HTTP API ์„ค๊ณ„์˜ ์—ฐ์žฅ์„ ์ด ๋˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ ๋ณต์Šตํ•˜๋Š” ๊ฒธ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด์ž

POST์™€ PUT์˜ ์ฐจ์ด์ 

  • POST์™€ PUT ๋ชจ๋‘ ์„œ๋ฒ„์— ์–ด๋–ค ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑ(๋“ฑ๋ก, ์ˆ˜์ •) ํ•  ์ˆ˜ ์žˆ์Œ
  • POST๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ URI ๊ฒฝ๋กœ๋ฅผ ๋ชจ๋ฅธ๋‹ค
    • ์„œ๋ฒ„๊ฐ€ ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ๋ฆฌ์†Œ์Šค URI ์ƒ์„ฑ โ†’ ์ปฌ๋ ‰์…˜
  • PUT์€ ํด๋ผ์ด์–ธํŠธ URI ๊ฒฝ๋กœ๋ฅผ ์•Œ๊ณ ์žˆ๋‹ค.
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ๋ฆฌ์†Œ์Šค์˜ URI๋ฅผ ์ง€์ • โ†’ ์Šคํ† ์–ด

์ผ๋ฐ˜์ ์œผ๋กœ ์ปฌ๋ ‰์…˜ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

PUT ๊ณผ PATCH

  • PUT์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์™„์ „ํ•˜๊ฒŒ ๋Œ€์ฒด โ†’๋ถ€๋ถ„ ์ˆ˜์ • ๋ถˆ๊ฐ€๋Šฅ
  • PATCH๋Š” ๋ถ€๋ถ„ ์ˆ˜์ • ๊ฐ€๋Šฅ

DB์˜ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” API๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ PATCH, POST๋ฅผ ํ†ตํ•ด์„œ ์„ค๊ณ„ํ•˜๋Š”๋ฐ PUT์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ถ€๋ถ„ ์ˆ˜์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๋ณด๋‚ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ

์ธํ„ฐ๋ŸฝํŠธ

๊ด€๋ จ๋œ ๋‚ด์šฉ์€ ์•„๋‹ˆ์ง€๋งŒ ํ•™์Šตํ•˜๋‹ค ์ด ์˜์ƒ์ด ๋˜๊ฒŒ ์œ ์šฉํ–ˆ๋˜๊ฑฐ ๊ฐ™์•„์„œ ๊ณต์œ ํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ธํ„ฐ๋ŸฝํŠธ

CPU๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์„ ๋•Œ, ์ž…์ถœ๋ ฅ ํ•˜๋“œ์›จ์–ด ๋“ฑ์˜ ์žฅ์น˜๋‚˜ ์˜ˆ์™ธ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜์—ฌ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ๋งˆ์ดํฌ๋กœํ”„๋กœ์„ธ์„œ์—๊ฒŒ ์•Œ๋ ค ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ

๋งˆ์ดํฌ๋กœํ”„๋กœ์„ธ์„œ(MPU) : ์ปดํ“จํ„ฐ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ธ ๊ธฐ๊ณ„์–ด๋ฅผ ํ•ด์„ํ•˜๊ณ , ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ”„๋กœ์„ธ์„œ(์ฃผ๋ณ€์žฅ์น˜๊ฐ€ ์žˆ์–ด์•ผ ๋™์ž‘/ ์š”์ฆ˜์—๋Š” CPU์™€ ๋™์ผํ•œ ์˜๋ฏธ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.)

์Šคํฌ๋ฆฐ์ƒท 2022-03-24 ์˜คํ›„ 5 52 20

๊ทธ๋Ÿผ ์œ„์— ์ •์˜๋ฅผ ์ข€ ํ’€์–ด์„œ ์„ค๋ช…ํ•ด๋ณด๋ฉด CPU๊ฐ€ ์ผ์„ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ๋‹ค๋ฅธ ์žฅ์น˜์—์„œ ์˜ˆ์™ธ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ด ์ž‘์—…์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ ์‹œ์ผœ์„œ CPU์—๊ฒŒ ๊ทธ ์ผ์„ ์‹œํ‚จ๋‹ค. ๊ทธ ์ •๋„ ์˜๋ฏธ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์™œ ๊ตณ์ด ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์„œ CPUํ•œํ…Œ ์ผ์„ ์‹œํ‚ฌ๊นŒ์š”? -> CPU์ด ์—ฐ์‚ฐ์†๋„๊ฐ€ ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค


์ธํ„ฐ๋ŸฝํŠธ๋Š” ํฌ๊ฒŒ 2๊ฐ€์ง€๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ•˜๋“œ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ : ํ‚ค๋ณด๋“œ, ๋งˆ์šฐ์Šค์™€ ๊ฐ™์€ ํ•˜๋“œ์›จ์–ด๊ฐ€ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ธํ„ฐ๋ŸฝํŠธ
  • ์†Œํ”„ํŠธ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ : ํ”„๋กœ๊ทธ๋žจ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์˜ˆ์™ธ์ƒํ™ฉ์ด ๋ฐœ์ƒ ํ•˜๊ฑฐ๋‚˜ ํ”„๋กœ๊ทธ๋žจ์ด ์ปค๋„ํ•จ์ˆ˜ ์‚ฌ์šฉ์„ ์œ„ํ•ด ํ˜ธ์ถœํ•˜๋Š” System call ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ
  • ์˜ˆ๋ฅผ ๋“ค๋ฉด, ๋‚ด๋ถ€์ ์ธ ํƒ€์ด๋จธ๊ฐ€ ์กด์žฌํ•ด์„œ 5์ดˆ๋งˆ๋‹ค ์–ด๋–ค ํŠน์ •ํ•œ ๋™์ž‘์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ 5์ดˆ๋งˆ๋‹ค ์†Œํ”„ํŠธ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์„œ ์–ด๋–ค ํŠน์ •ํ•œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์–ด๋–ค ํŠน์ •ํ•œ ํ•˜๋“œ์›จ์–ด ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ ๋งˆ๋‹ค ํŠน์ •ํ•œ ๋™์ž‘์ด ์ผ์–ด๋‚˜๋„๋ก ํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•˜๋“œ์›จ์–ด ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์„œ ํŠน์ • ๋™์ž‘์„ ์‹คํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ๊ณผ์ •์— ๋Œ€ํ•ด์„œ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1) ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ ๋ช…๋ น์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ํฌํ•จํ•œ ๋ถ€๊ฐ€ ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค

์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ธํ„ฐ๋ŸฝํŠธ ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰์‹œ์ผœ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ CPU์—์„œ ์ž‘์—…์ค‘์ด์˜€๋˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ PCB๋ฅผ ํ†ตํ•ด์„œ ํ˜„์žฌ ์‹คํ–‰์ค‘์ด๋˜ ์ฝ”๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ, ๋ ˆ์ง€์Šคํ„ฐ๊ฐ’, ํ•˜๋“œ์›จ์–ด ์ƒํƒœ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

2) ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ(ISR)

์šด์˜์ฒด์ œ๋Š” ๋ฏธ๋ฆฌ ์ธํ„ฐ๋ŸฝํŠธ ๋ฒกํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ ์ธํ„ฐ๋ŸฝํŠธ ๋ฒกํ„ฐ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉด ์‹ค์ œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ฝ”๋“œ๋Š” ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ณณ์— ์ •์˜ ๋˜์–ด ์žˆ๊ณ  ์ด๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
ํ•™๋ถ€์‹œ์ ˆ ๊ธฐ์–ต์„ ๋– ์˜ฌ๋ ค๋ณด๋ฉด ์ธํ„ฐ๋ŸฝํŠธ์— ํ•ด๋‹นํ•˜๋Š” ์ฃผ์†Œ๊ฐ’์ด ์ด๋ฏธ ์„ค๊ณ„ํ•  ๋•Œ ๋ฏธ๋ฆฌ ์ •ํ•ด์ ธ์žˆ์—ˆ๋˜๊ฑธ๋กœ ๊ธฐ์–ตํ•˜๋Š”๋ฐ ๊ทธ ๋ถ€๋ถ„์„ ์ธํ„ฐ๋ŸฝํŠธ ๋ฒกํ„ฐ๋ผ๊ณ  ํ•˜๋Š”๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค

3) ์ธํ„ฐ๋ŸฝํŠธ ์ „์œผ๋กœ ๋ณต์›

์ธํ„ฐ๋ŸฝํŠธ์—์„œ ์š”๊ตฌํ•˜๋Š” ์ž‘์—…์„ ๋ชจ๋‘ ์™„๋ฃŒํ•˜๋ฉด ์›๋ž˜ CPU๊ฐ€ ํ•˜๋˜ ์ž‘์—…์„ ์ด์–ด์„œ ํ•˜๋Š” ๊ณผ์ •์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.(์•„๊นŒ PCB์— ์ €์žฅํ•ด๋†จ์œผ๋‹ˆ๊นŒ ๋Œ์•„์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)


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

๋”ฅ๋งํฌ - 02

์™œ .onOpenURL์ด ๋™์ž‘ํ•˜์ง€ ์•Š์„๊นŒ?

ํ”„๋กœ์ ํŠธ ๋ ˆํฌ

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

๊ฒฐ๋ก ๋ถ€ํ„ฐ ์–˜๊ธฐํ•˜์ž๋ฉด SwiftUI ๊ธฐ๋ฐ˜์ด ์•„๋‹Œ UIKit ๊ธฐ๋ฐ˜์˜ RootView๋ฅผ ๋ฐ”๊พธ๋Š” ๋™์ž‘์ด ๋ฌธ์ œ์˜€๋‹ค.

let window = UIApplication.shared
              .connectedScenes
              .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
              .first { $0.isKeyWindow }

guard let window = window else { return }
let tabViewModel = TestTabViewModel()
window.rootViewController = UIHostingController(
  rootView: TestTabView().environmentObject(tabViewModel)
)

window.makeKeyAndVisible()
UIView.transition(
  with: window,
  duration: 0.5,
  options: .transitionCrossDissolve,
  animations: nil,
  completion: nil
)

๊ธฐ์กด์—๋Š” ํŠน์ • ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋๋‚˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ RootView๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” ๋ฐฉ์‹์„ ์ด์šฉํ•ด์„œ ํ™”๋ฉด ์ „ํ™˜์„ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

์ •ํ™•ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋ฉด

  • Lottie๋ฅผ ์ด์šฉํ•œ ์Šคํ”Œ๋ž˜์‰ฌ ๋ทฐ๋ฅผ ์‹คํ–‰
  • ํ•ด๋‹น ๋ทฐ์—์„œ ์ฒ˜์Œ ์•ฑ์ด ์‹คํ–‰๋  ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ›์•„์˜ด
  • ํ† ํฐ์ด ์œ ํšจํ•œ์ง€๋ฅผ ํ™•์ธ

์œ„์˜ 3๊ฐ€์ง€ ๋กœ์ง์„ ํƒ€๋ฉด์„œ ์„ฑ๊ณต ์œ ๋ฌด์— ๋”ฐ๋ผ ์‹œ์ž‘ ํ•˜๋Š” ํ™”๋ฉด์„ ์Šคํ”Œ๋ž˜์‰ฌ ๋ทฐ์—์„œ UIKit ๊ธฐ๋ฐ˜์˜ RootView๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ† ์ด ํ”„๋กœ์ ํŠธ์—์„œ ํ™•์ธํ–ˆ๋˜ .openURL ์ด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค ใ… ใ… 
์‚ฌ์‹ค ์ •ํ™•ํ•œ ์ด์œ ์™€ ํ•จ๊ป˜ ์ •๋ฆฌํ•˜๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ ๋ฐ€๋ฆฐ ์ผ์ด ์‚ฐ๋”๋ฏธ๋ผ ์šฐ์„  ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์ด๋ผ๋„ ์ •๋ฆฌํ•ด๋†“๊ณ ์ž ํ•œ๋‹ค.

struct AppRootView: View {
  @StateObject
  var viewModel = AppRootViewModel()

  var body: some View {
    Group {
      switch viewModel.nextView {
      case .splash:
        SplashView()
      case .main:
        TodoTabView()
      }
    }
  }
}
final class AppRootViewModel: ObservableObject {
  enum NextView {
    case splash
    case main
//    case login
  }

  @Published var nextView: NextView = .splash

  init() {
    fetchInitInfo()
  }
}

extension AppRootViewModel {
// BL์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌ
  func fetchInitInfo() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
      guard let self = self else { return }
      self.nextView = .main
    }
  }
}

ํ† ์ด ํ”„๋กœ์ ํŠธ๋ผ Lottie ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ ๋ทฐ๋ชจ๋ธ์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์ „๋ถ€ ์ƒ๋žตํ–ˆ๋‹ค.

๊ธฐ์กด์˜ RootViewCon์„ ๋ฐ”๊พธ๋Š” ๋กœ์ง์„ ๊ฑท์–ด๋‚ด๊ณ  AppRootView๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ nextView๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

Optional

Optional

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-06 แ„‹แ…ฉแ„’แ…ฎ 2 56 11

  • ์šฐ์„  ์˜ต์…”๋„์˜ ์›ํ˜•์„ ํ™•์ธํ•ด๋ณด๋ฉด ๋†€๋ž๊ฒŒ๋„ Optional์ด ์—ด๊ฑฐํ˜• ๊ทธ๋ฆฌ๊ณ  ์ œ๋„ค๋ฆญ(Wrapped)์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ExpressibleByNilLiteral ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
var optionalValue: Optional<Int> = nil

if optionalValue == .none {
  print("This Value is nil")
}

if optionalValue == nil {
  print("This Value is nil")
}

์›ํ˜•์ด ์—ด๊ฑฐํ˜•์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹น์—ฐํžˆ ์œ„์™€ ๊ฐ™์ด ํ™•์ธ ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋จผ์ € ExpressibleByNilLiteral ํ”„๋กœํ† ์ฝœ์˜ ์˜๋ฏธ๋ฅผ ํ™•์ธํ•ด๋ณด์ž

ExpressibleByNilLiteral ํ”„๋กœํ† ์ฝœ์€ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ nil๋กœ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค
์œ„์˜ ๋ฌธ์žฅ์ด ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ํƒ€์ž… ์ถ”๋ก ์„ ํ†ตํ•ด์„œ ๋ณ€์ˆ˜๋‚˜ ์ƒ์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™” ํ–ˆ๋˜ ๊ฒƒ์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋œ๋‹ค.

var name = "Sangwon" // ์–ด๋–ป๊ฒŒ ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด์„ ํ†ตํ•ด์„œ ํƒ€์ž…์ถ”๋ก ์ด ๊ฐ€๋Šฅํ–ˆ์„๊นŒ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-06 แ„‹แ…ฉแ„’แ…ฎ 3 20 11

์ด๋Š” String์ด ExpressibleByStringLiteral ํ”„๋กœํ† ์ฝœ์ด ์ฑ„ํƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ–ˆ๋‹ค.

public init(_ some: Wrapped) // Optional Value
public init(nilLiteral: ()) // nil Value

๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑ์ž๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด 2๊ฐœ์˜ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Swift Source Code ๋ณด์ถฉํ•˜๊ธฐ!

์Šคํ† ๋ฆฌ๋ณด๋“œ์™€ Xib

์Šคํ† ๋ฆฌ๋ณด๋“œ์™€ xib

์ผ๋ฐ˜์ ์œผ๋กœ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ์—ฌ๋Ÿฌ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ๋“ค์„ ๋งŒ๋“ค์–ด์„œ ์•ฑ์˜ ํ™”๋ฉด๊ณผ ์ „์ฒด์ ์ธ ํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  table view cell, collection view cell, custom view๋“ค์„ xibํŒŒ์ผ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด ๋‘˜์€ ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ?

Untitled Untitled 1

์šฐ์„  ์ปดํŒŒ์ผ ์ดํ›„ ์ƒ์„ฑ๋˜๋Š” ํŒŒ์ผ์„ ํ™•์ธํ•ด๋ณด๋ฉด xib ํŒŒ์ผ์€ nib์œผ๋กœ ์Šคํ† ๋ฆฌ๋ณด๋“œ๋Š” stroyboardc๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

storyboardc ํŒŒ์ผ์— ์ƒ์„ฑ๋œ ์ € ์˜๋ฌธ์˜ nibํŒŒ์ผ๋“ค์€ ๋ฌด์—‡์ผ๊นŒ?

<viewController storyboardIdentifier="Test" id="hef-Go-4NS" customClass="TestViewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">

<viewController id="BYZ-38-t0r" customClass="ViewController">

์•ˆํƒ€๊น๊ฒŒ๋„ nibํŒŒ์ผ์„ ์—ด์–ด๋ณด๋Š”๊ฑด ์œ ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด๋ผ ํ™•์ธ์„ ํ•ด๋ณด์ง€ ๋ชปํ–ˆ์ง€๋งŒ ์Šคํ† ๋ฆฌ๋ณด๋“œ ํŒŒ์ผ์„ ์†Œ์Šค์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด viewcontroller์™€ view์˜ ID๋กœ ํŒŒ์ผ๋ช…์ด ์ƒ์„ฑ๋œ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Untitled 2

storyboardc ํŒŒ์ผ์— ํ•จ๊ป˜ ์ƒ์„ฑ๋˜๋Š” info.plist ํŒŒ์ผ์„ ํ™•์ธํ•ด๋ณด๋ฉด ์•„๋ž˜ 3๊ฐœ์˜ ํŒŒ์ผ๋ช…์ดUIViewControllerIdentifiersToNibNames์ธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น value ๊ฐ’์€ storyboard ID์˜ ๊ฐ’๊ณผ ๋™์ผํ•œ๊ฒƒ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@IBAction func mainButtonTapped(_ sender: UIButton) {
    print("Touch Event")
    let sb = UIStoryboard(name: "Main", bundle: nil)
    let vc = sb.instantiateViewController(withIdentifier: StaticTableViewController.storyboardID)
    navigationController?.pushViewController(vc, animated: true)
  }

๊ทธ๋Ÿผ ์ด์ œ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ Segue๊ฐ€ ์•„๋‹Œ navigation push๋กœ ๊ตฌํ˜„ํ•  ๋•Œ identifier๋ฅผ ์„ค์ •ํ•ด์•ผ ํ–ˆ๋˜ ์ด์œ ๋ฅผ ๋ช…ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ๋‹ค!

๊ทธ๋Ÿผ xib ํŒŒ์ผ์„ ์ปดํŒŒ์ผ ํ–ˆ์„๋•Œ๋„ nibํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ณ  ์Šคํ† ๋ฆฌ๋ณด๋“œ๋ฅผ ์ปดํŒŒ์ผ ํ–ˆ์„ ๋•Œ๋„ nibํŒŒ์ผ๋“ค๊ณผ info.plist ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋Š”๋ฐ ๊ทธ ๋‘˜์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ผ๊นŒ?

// SB
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB">
// Xib
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB">

์Šคํ† ๋ฆฌ๋ณด๋“œ์™€ xibํŒŒ์ผ์„ ๋ชจ๋‘ ์†Œ์Šค์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด xml๋กœ ํ‘œํ˜„๋œ xibํŒŒ์ผ์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ ์Šคํ† ๋ฆฌ๋ณด๋“œ์™€ xib๋Š” ๋ฌด์—‡์ด ๋‹ค๋ฅธ๊ฑธ๊นŒ?

Untitled 3

์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ xibํŒŒ์ผ๋กœ ์ƒ์„ฑํ•˜๋Š” cell, custom view๋“ค์€ ํ•˜๋‚˜์˜ ๋ทฐ ์ •๋ณด๋งŒ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๋ฐ˜๋ฉด ์Šคํ† ๋ฆฌ๋ณด๋“œ๋Š” ์—ฌ๋Ÿฌ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ xibํŒŒ์ผ๋“ค๊ณผ ๋ทฐ ๊ด€๊ณ„์ •๋ณด๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ํŒŒ์ผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค

๋Œ€์นญํ‚ค์™€ ๋น„๋Œ€์นญํ‚ค

๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”

Untitled

์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”์— ๊ฐ™์€ ๊ฐ™์€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์˜๋ฏธํ•œ๋‹ค.

์ฆ‰, ํด๋ผ์ด์–ธํŠธ์—์„œ ๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด์„œ Request Body๋ฅผ ์•”ํ˜ธํ™” ์‹œ์ผœ์„œ ๋ณด๋‚ด๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ ์„œ๋ฒ„์—์„œ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ณตํ˜ธํ™” ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์•”ํ˜ธํ™”ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ–ˆ๋˜ ํ‚ค๋ฅผ ์„œ๋ฒ„์—๋„ ๋ณด๋‚ด์ค˜์•ผ ํ•œ๋‹ค

๊ทธ๋Ÿผ ๋จธ๋ฆฌ์†์—์„œ ์ด๋Ÿฐ ์˜๋ฌธ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋– ์˜ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ทธ๋Ÿผ ์„œ๋ฒ„๋กœ ๋Œ€์นญํ‚ค๋Š” ์–ด๋–ป๊ฒŒ ๋ณด๋‚ด์ค˜์•ผ ํ•˜๋Š” ๊ฑธ๊นŒ?
  • ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ Request Body๋ฅผ ์•”ํ˜ธํ™” ํ–ˆ๋Š”๋ฐ ๋ณตํ˜ธํ™”๋ฅผ ์œ„ํ•œ ํ‚ค๋ฅผ ์•„๋ฌด๋Ÿฐ ๋ณด์•ˆ ์—†์ด ๋ณด๋‚ด๋ฉด ์•”ํ˜ธํ™”๋Š” ์˜๋ฏธ๊ฐ€ ์—†์–ด์งˆ ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?

์‹ค์ œ๋กœ ๋Œ€์นญํ‚ค๋ฅผ ์•”ํ˜ธํ™”๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ๋Œ€์นญํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

์‹ค์ œ ๋ณด์•ˆ์— ๋Œ€ํ•ด ์กฐ์˜ˆ๊ฐ€ ๊นŠ์ง€ ์•Š์•„ ๋Œ€์นญํ‚ค๋ฅผ ์–ด๋–ป๊ฒŒ ์•ˆ์ „ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜์ง€์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์•Œ์ง€ ๋ชปํ•˜์ง€๋งŒ ์•”ํ˜ธํ™”-๋ณตํ˜ธํ™”ํ•  ๋‚ด์šฉ์„ ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋ฅผ ์ด์šฉํ•˜๊ณ  ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋ฅผ ๋‹ค์‹œ ๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋ฅผ ํ†ตํ•ด์„œ ์„œ๋ฒ„์— ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ณด์•ˆ์ƒ ๋‹จ์ ์—๋„ ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”์— ๋น„ํ•ด ์—ฐ์‚ฐ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค

๋Œ€ํ‘œ์ ์ธ ๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ๋Š”

  • DES
  • AES
  • SEED

๋“ฑ๋“ฑ์ด ์žˆ๊ณ  AES ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณผ ์˜ˆ์ •์ด๋‹ค.


๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”(๊ณต๊ฐœํ‚ค)

Untitled 1

๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋Š” ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”์— ์„œ๋กœ ๋‹ค๋ฅธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์˜๋ฏธํ•œ๋‹ค

์œ„์˜ ๊ทธ๋ฆผ์„ ์˜ˆ์‹œ๋กœ ๋“ค๋ฉด

  • ์„œ๋ฒ„์—์„œ ์•”ํ˜ธํ™” ๋ณตํ˜ธํ™”๋ฅผ ์œ„ํ•œ Key Pair๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • ๊ฐœ์ธํ‚ค๋Š” ์„œ๋ฒ„์— ์ €์žฅ๋˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ๊ณต๊ฐœํ‚ค๋ฅผ ์ œ๊ณตํ•œ๋‹ค
  • ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด Request Body๋ฅผ ์•”ํ˜ธํ™” ํ•œ๋‹ค
  • ์„œ๋ฒ„๋Š” ์•”ํ˜ธํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐœ์ธํ‚ค๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”ํ•œ๋‹ค

๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด ์•”ํ˜ธํ™”๋œ ๋ฐ์ดํ„ฐ๋Š” ๊ฐœ์ธํ‚ค๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋ณตํ˜ธํ™” ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์€ ๊ณผ์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค

๊ทธ๋Ÿผ ๊ฐœ์ธํ‚ค๋ฅผ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”ํ•˜๊ณ  ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”๋ฅผ ํ•  ์ˆ˜๋Š” ์—†์„๊นŒ? ๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๊ณต๊ฐœํ‚ค๋Š” ๋ˆ„๊ตฌ๋‚˜ ์–ป์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ˆ„๊ตฌ๋‚˜ ์•”ํ˜ธํ™” ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณตํ˜ธํ™” ํ•  ์ˆ˜ ์žˆ๊ฐœ ๋•Œ๋ฌธ์— ๋ณด์•ˆ์ ์ธ ์ธก๋ฉด์—์„œ๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š์ง€๋งŒ ์•”ํ˜ธํ™” ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณตํ˜ธํ™” ํ–ˆ์„ ๋•Œ ์ด์ „ ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€์ง€๋งŒ ํ™•์ธํ•˜๋ฉด ๋˜๋Š” ๋””์ง€ํ„ธ ์„œ๋ช…์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

  • A๋Š” ๊ฐœ์ธํ‚ค๋กœ ์„œ๋ช…ํ•˜๋ ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ณ  ์›๋ณธ๊ณผ ์„œ๋ช… ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ธ๋‹ค
  • B๋Š” ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด์„œ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ ๋ณตํ˜ธํ™” ํ•œ๋‹ค
  • ๋ณตํ˜ธํ™”ํ•œ ๋ฐ์ดํ„ฐ์™€ ์›๋ณธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค

B์ž…์žฅ์—์„œ ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉด A๊ฐ€ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋ณด๋ƒˆ์Œ์ด ๋ณด์žฅ๋˜๊ณ  ๋ณตํ˜ธํ™” ํ•œ ๋ฐ์ดํ„ฐ์™€ ์›๋ณธ์ด ๊ฐ™์œผ๋ฉด ๋ฐ์ดํ„ฐ์— ์œ„์กฐ๊ฐ€ ์—†์Œ์ด ๋ณด์žฅ๋œ๋‹ค.

์•ž์„œ ์‚ดํŽด๋ณธ ๋Œ€์นญํ‚ค์— ๋น„ํ•ด ๋ณด์•ˆ์ ์œผ๋กœ ์žฅ์ ์ด ์žˆ์ง€๋งŒ ์—ฐ์‚ฐ๋Ÿ‰์ด ๋งŽ์•„ ๋Š๋ฆฌ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

๋Œ€ํ‘œ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ

  • RSA
  • DSA, ECDSA

๋“ฑ๋“ฑ์ด ์žˆ๊ณ  RSA ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•œ ์•”ํ˜ธํ™”-๋ณตํ˜ธํ™” ๊ณผ์ •, ECDSA๋ฅผ ํ†ตํ•œ ์„œ๋ช…, ์„œ๋ช…๊ฒ€์ฆ ๊ณผ์ •์„ ๊ตฌํ˜„ํ•ด๋ณผ ์˜ˆ์ •์ด๋‹ค.

์‹œ์Šคํ…œ ์ฝœ

์‹œ์Šคํ…œ์ฝœ์ด๋ž€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ปดํ“จํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์‹œ์Šคํ…œ์ธ ์šด์˜์ฒด์ œ(OS)์—๊ฒŒ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ด๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•  ๋–„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด์ „์— ํ”„๋กœ์„ธ์Šค๋Š” ์šด์˜์ฒด์ œ๋กœ ๋ถ€ํ„ฐ ์ž์›์„ ํ• ๋‹น๋ฐ›๋Š” ์ž‘์—…์˜ ๋‹จ์œ„๋ผ๊ณ  ๊ณต๋ถ€ ํ–ˆ๋Š”๋ฐ ๋งŒ์•ฝ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž๊ธฐ ํ”„๋กœ๊ทธ๋žจ ์ด์™ธ์˜ ํŠน์ • ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•œ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

ํ”„๋กœ์„ธ์Šค๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์šด์˜์ฒด์ œ์— ์š”์ฒญ์„ ํ†ตํ•ด์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๊ณ  ์ด๋Ÿฐ ์š”์ฒญ์„ ์‹œ์Šคํ…œ์ฝœ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์šด์˜์ฒด์ œ๋Š” User Mode์™€ Kernel Mode๋กœ ๋…๋ฆฝ๋œ ๋™์ž‘ ๋ชจ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์•ž์„œ ๋งํ•œ ์ƒํ™ฉ์ฒ˜๋Ÿผ, ํ”„๋กœ๊ทธ๋žจ์ด ๊ตฌ๋™๋˜๋Š”๋ฐ ํŒŒ์ผ์„ ์ฝ์–ด ์˜ค๊ฑฐ๋‚˜, ์“ฐ๊ฑฐ๋‚˜, ์ถœ๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์€ Kernel Mode๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€๋Šฅํ•ฉ๋‚˜๋””.

์ฆ‰, ์ •๋ฆฌํ•˜์ž๋ฉด ์‹œ์Šคํ…œ์ฝœ์€ ์ปค๋„ ์˜์—ญ์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ์ž ๋ชจ๋“œ๊ฐ€ ์‚ฌ์šฉ๊ฐ€๋Šฅ ํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํด๋กœ์ € - 03

@autoclosure

์•„๋งˆ Swift๋กœ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ ‘ํ•ด๋ณด์‹  ๋ถ„๋“ค์€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์›ํ˜•์„ ๊ด€์ฐฐํ•ด๋ณด๋ฉด @autoclosure๋ผ๋Š” attribute๋ฅผ ๋ณธ์ ์ด ์žˆ์„ํ…๋ฐ์š”. ํ˜น์‹œ ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š”์ง€๋„ ์ •ํ™•ํžˆ ์•Œ๊ณ  ๊ณ„์‹ ๊ฐ€์š”?? (์ €๋Š” ๋ชฐ๋ž๋‹ต๋‹ˆ๋‹ค~)

{ } ์—†์ด ํ‘œํ˜„์‹๋งŒ ์ ์–ด๋„ ํด๋กœ์ €๋ฅผ ๋ž˜ํ•‘ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ

์ž๋™์œผ๋กœ ํด๋กœ์ €๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ๋Œ€์ฒด ์™œ ํ•„์š”ํ•œ๊ฑธ๊นŒ์š”โ“ย ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด์„œ ํ•œ๋ฒˆ ์ดํ•ด ํ•ด๋ด…์‹œ๋‹ค.

func goodMorning(morning: Bool, whom: String) {
    if morning {
        print("Good Morning, \(whom)")
    }
}

func giveName() -> String {
    print(#function, ": Called")
    return "Bran"
}

goodMorning(morning: true, whom: "์‹ ์ƒ") // Good Morning, ์‹ ์ƒ
goodMorning(morning: false, whom: giveName()) // giveName(): Called

๋งค๊ฐœ๋ณ€์ˆ˜ whom์˜ ํƒ€์ž…์˜ String ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— String ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” giveName()์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ฉ”์„œ๋“œ ๊ตฌ์กฐ์—์„œ๋Š” whom ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‹œ์ ์—๋„ ๊ฐ’์„ ๋ณต์‚ฌํ•ด์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. whom์ด๋ผ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” morning์ด true์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š”๋ฐ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ์ธ์žgiveName()์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ฃ .

์œ„์˜ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ์‚ฌ์‹ค ๋ฐฉ๋ฒ•์ด์•ผ ๋‹ค์–‘ํ•˜๊ฒŒ ์žˆ๊ฒ ์ง€๋งŒ ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค์ง€ ์•Š๋Š” ํด๋กœ์ €์˜ ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Lazy evaluation

func goodMorning(morning: Bool, whom: () -> String) {
    if morning {
        print("Good Morning, \(whom())")
    }
}

func giveName() -> String {
    print(#function, ": Called")
    return "Bran"
}

goodMorning(morning: true, whom: "์‹ ์ƒ") // Error
goodMorning(morning: true, whom: {"์‹ ์ƒ"}) // Good Morning, ์‹ ์ƒ
goodMorning(morning: false, whom: giveName) // 

morning์ด false์ธ ๊ฒฝ์šฐ์—๋Š” () โ†’ String ํƒ€์ž…์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(=ํด๋กœ์ € ํ˜•ํƒœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ whom์€ ์ธ์ž๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ „๋‹ฌ๋˜๋Š” ์‹œ์ ์ด ์•„๋‹Œ ํ•จ์ˆ˜๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ์‹คํ–‰๋˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.)

ํ•˜์ž๋งŒ, whom ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํƒ€์ž…์ด ๋ช…์‹œ์ ์ธ ํด๋กœ์ €๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ ์ด์ „์˜ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ String ํƒ€์ž…์˜ ์ƒ์ˆ˜๋‚˜ ๋ณ€์ˆ˜๋ฅผ ์ธ๋กœ์ž ๋„˜๊ฒจ์ค„ ์ˆ˜ ์—†๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ์ด๋•Œ autoclosure๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

func goodMorning3(morning: Bool, whom: @autoclosure () -> String) {
    if morning {
        print("Good Morning, \(whom())")
    }
}

goodMorning3(morning: false, whom: "์‹ ์ƒ") //
goodMorning3(morning: true, whom: "๋„ค์นด") // Good Morning, ์‹ ์ƒ
goodMorning3(morning: true, whom: giveName()) // giveName() : Called
																							// Good Morning, Bran

์ฆ‰ autoclosure๋ฅผ ์ด์šฉํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋”ฐ๋กœ { } ์—†์ด ํ‘œํ˜„์‹๋งŒ ์ ์–ด๋„ ์ž๋™์œผ๋กœ ํด๋กœ์ €๋กœ ๋ž˜ํ•‘ํ•ด์ค๋‹ˆ๋‹ค.


autoclosure๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

1) ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์€ ํด๋กœ์ €

ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ autoclosure attribute๋ฅผ ์ด์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ, ํ•จ์ˆ˜์˜ ์›ํ˜•์„ ์ž˜ ๋“ค์—ฌ๋‹ค ๋ณด์ง€ ์•Š์œผ๋ฉด ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด ํด๋กœ์ €์˜ ๋ฐ˜ํ™˜ํƒ€์ž…์œผ๋กœ ์ฐฉ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์ธ์ž๋Š” ๋ฐ˜ํ™˜ํƒ€์ž…์˜ ์ƒ์ˆ˜๋‚˜ ๋ณ€์ˆ˜๋ฅผ ์ ์–ด๋„ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ์š”..

ํ•ด๋‹น ์‚ฌ์‹ค์„ ๋ชจ๋ฅด๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํƒ€์ž…์„ ์ž˜๋ชป ์ธ์ง€ํ•˜๋Š” ๊ฒƒ๋„ ์ถฉ๋ถ„ํžˆ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋” ํฐ ๋ฌธ์ œ๋Š” ์‹ค์ œ ํƒ€์ž…์ด ํด๋กœ์ €๋ผ๋Š”๋ฐ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์„œ์„œ ํด๋กœ์ €๋Š” ์‚ฌ์šฉํ•˜๋ฉด ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š” **Lazy evaluation ํŠน์ง•์ด ์žˆ๋‹ค๊ณ  ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ฝ”๋“œ์— ๋”ฐ๋ผ์„œ ํด๋กœ์ €์˜ **Lazy evaluation ํŠน์ง• ๋•Œ๋ฌธ์— ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2) autoclosure ๋Š” argument ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฉฐ ๋ฆฌํ„ด๊ฐ’์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

() โ†’ T ํ˜•ํƒœ์˜ ํด๋กœ์ €๋งŒ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ

[@autoclosure what, why and when](https://medium.com/ios-os-x-development/https-medium-com-pavelgnatyuk-autoclosure-what-why-and-when-swift-641dba585ece)

N์ฝ”์–ด M์Šค๋ ˆ๋“œ

N์ฝ”์–ด M์Šค๋ ˆ๋“œ

CPU์—์„œ N์ฝ”์–ด์˜ M์Šค๋ ˆ๋“œ๋Š” ๋ฌผ๋ฆฌ์ ์ธ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜์™€ ๋…ผ๋ฆฌ์ ์ธ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค

๋ชจ๋“  ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ฒฐ๊ตญ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ์™€ CPU ์ž์›์„ ํ†ตํ•ด ์—ฐ์‚ฐ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค.

ํ•˜์ง€๋งŒ ๊ณ ์ „์ ์ธ CPU๋Š” ์ด๋Ÿฐ ์—ฐ์‚ฐ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”๊ฒŒ ํ•˜๋‚˜๋ฐ–์— ์—†์—ˆ์ง€๋งŒ ์ตœ๊ทผ์—๋Š” ์ฝ”์–ด์˜ ๋“ฑ์žฅ์œผ๋กœ ์ด๋Ÿฐ ๋ฌผ๋ฆฌ์ ์ธ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ๋‹›์ด CPU๋‚ด๋ถ€์— ์—ฌ๋Ÿฌ๊ฐœ ์กด์žฌํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

์ฝ”์–ด์˜ ๋“ฑ์žฅ์— ๋”ฐ๋ผ์„œ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค์˜ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

Untitled

๊ทธ๋Ÿผ ์šฐ๋ฆฌ๊ฐ€ CPU๋ฅผ ์‚ด ๋•Œ ์ ‘ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋Š” ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ์ด์•ผ๊ธฐ ํ•˜๋ฉด, ์ด๋•Œ ์Šค๋ ˆ๋“œ๋Š” OS๊ฐ€ ์ธ์‹ํ•˜๋Š” ๋…ผ๋ฆฌ์ ์ธ ์ฝ”์–ด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด์„œ ์Šค๋ ˆ๋“œ์˜ ๊ฐœ๋…๊ณผ ํ•˜์ดํผ ์“ฐ๋ ˆ๋”ฉ์„ ์ดํ•ด ํ•ด๋ณด์ž.

์ฝ”์–ด์˜ ๋“ฑ์žฅ์œผ๋กœ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜ ๋งŒํผ ํ”„๋กœ์„ธ์Šค์˜ ์ž‘์—…์„ ๋™์‹œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฐ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์†๋„๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค. (ํ•ญ์ƒ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค..)

๊ทธ๋Ÿผ ์—ฌ๊ธฐ์„œ ํ•œ์ •๋œ ์ž์›์œผ๋กœ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์„๊นŒ?

์—ฌ๊ธฐ์„œ ๋“ฑ์žฅํ•˜๋Š” ๊ธฐ์ˆ ์ด ํ•˜์ดํผ์“ฐ๋ ˆ๋”ฉ์ด๋‹ค.

ํ•˜์ดํผ ์“ฐ๋ ˆ๋”ฉ์ด ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ๊ฐœ๋…์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€๊นŒ์ง€๋Š” ์ฐพ์•„๋ณด์ง€ ๋ชปํ–ˆ์ง€๋งŒ 
CPU๊ฐ€ ํ•˜์ดํผ ์“ฐ๋ ˆ๋”ฉ ๊ธฐ์ˆ ์„ ์ด์šฉํ•ด์„œ OS์—๊ฒŒ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์†์ธ๋‹ค ์ •๋„๋กœ ์ดํ•ดํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

์ฆ‰ 4์ฝ”์–ด 8์Šค๋ ˆ๋“œ์˜ cpu๋Š” ์‹ค์ œ ๋ฌผ๋ฆฌ์ ์œผ๋กœ๋Š” 4๊ฐœ์˜ ์ฝ”์–ด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ OS์ƒ์—์„œ๋Š” 8๊ฐœ์˜ ๋…ผ๋ฆฌ์  ์ฝ”์–ด๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜์–ด์„œ 8๊ฐœ์˜ ์ž‘์—…์„ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.


ํ•ด๋‹น ๋‚ด์šฉ๊ณผ ๋ณ„๊ฐœ๋กœ ๊ฐœ์ธ์ ์œผ๋กœ ์Šค๋ ˆ๋“œ๋ผ๋Š” ์šฉ์–ด๋ฅผ ๋„ˆ๋ฌด ๋ณตํ•ฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์„œ ๊ฐœ๋…์„ ์žก๊ธฐ ์–ด๋ ค์› ์—ˆ๋Š”๋ฐ ํ•˜๋“œ์›จ์–ด์ ์ธ ์Šค๋ ˆ๋“œ์™€ ์†Œํ”„ํŠธ์›จ์–ด์ ์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

  • ์†Œํ”„ํŠธ์›จ์–ด์  ์Šค๋ ˆ๋“œ๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์‹คํ–‰ ํ๋ฆ„์˜ ๋‹จ์œ„๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • ํ•˜๋“œ์›จ์–ด์  ์Šค๋ ˆ๋“œ๋Š” ๋…ผ๋ฆฌ์ ์ธ ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ

ํ”„๋กœ์„ธ์Šค ์ฃผ์†Œ๊ณต๊ฐ„

ํ”„๋กœ์„ธ์Šค๋Š” ์šด์˜์ฒด์ œ๋กœ ๋ถ€ํ„ฐ ์ž์›์„ ํ• ๋‹น๋ฐ›๋Š” ์ž‘์—…์˜ ๋‹จ์œ„์ด๊ณ 
์šด์˜์ฒด์ œ๋กœ ๋ถ€ํ„ฐ ํ• ๋‹น๋ฐ›์€ ์ž์›์€ ๋…๋ฆฝ๋œ Heap, Data, Stack, Code ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ํ”„๋กœ์„ธ์Šค ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ๋Œ€ํ•ด์„œ ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-03-27 แ„‹แ…ฉแ„’แ…ฎ 7 51 40

Code(TEXT)

  • ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ๋ถ€๋ถ„์œผ๋กœ ์‹คํ–‰ํ•  ํ”„๋กœ๊ทธ๋žจ์˜ ์ฝ”๋“œ๊ฐ€ ์ €์žฅ๋˜๋Š” ์˜์—ญ
  • ํ•จ์ˆ˜, ์ œ์–ด๋ฌธ, ์ƒ์ˆ˜๋“ฑ์ด ์—ฌ๊ธฐ์— ์ง€์ •๋œ๋‹ค
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ •๋˜๊ณ  ์ค‘๊ฐ„์— ์ฝ”๋“œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋„๋ก Read-Only

Data

  • ํ”„๋กœ๊ทธ๋žจ์˜ ์ „์—ญ๋ณ€์ˆ˜์™€ ์ •์ ๋ณ€์ˆ˜๊ฐ€ ์ €์žฅ๋˜๋Š” ์˜์—ญ -> ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ํ•ญ์ƒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋ณ€์ˆ˜๊ฐ€ ์ €์žฅ
  • ๋ฐ์ดํ„ฐ ์˜์—ญ์€ ํ”„๋กœ๊ทธ๋žจ์˜ ์‹œ์ž‘๊ณผ ํ•จ๊ป˜ ํ• ๋‹น๋˜๋ฉฐ, ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜๋ฉด ์†Œ๋ฉธํ•œ๋‹ค
  • ์‹คํ–‰์ค‘์—๋„ ์ „์—ญ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ Read-Write
  • ์ดˆ๊ธฐํ™”๋œ ๋ฐ์ดํ„ฐ๋Š” Data ์˜์—ญ์— ์ €์žฅ๋˜๊ณ , ์ดˆ๊ธฐํ™” ๋˜์ง€์•Š์€ ๋ฐ์ดํ„ฐ๋Š” BSS ์˜์—ญ์— ์ €์žฅ๋œ๋‹ค.

Stack

  • ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ๊ด€ ๊ด€๊ณ„๋˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜์™€ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ €์žฅ๋˜๋Š” ์˜์—ญ
  • Stack์€ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ๊ณผ ํ•จ๊ป˜ ํ• ๋‹น๋˜๋ฉฐ, ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜๋ฉด ์†Œ๋ฉธํ•œ๋‹ค
  • Heap ์˜์—ญ์— ์ƒ์„ฑ๋œ Object ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ ์ฐธ์กฐ๊ฐ’์ด ํ• ๋‹น๋œ๋‹ค. (์ธ์Šคํ„ฐ์Šค ์ƒ์„ฑ์‹œ ์ฃผ์†Œ๊ฐ’์ด Stack์— ์ €์žฅ๋œ๋‹ค)
  • ๋ฉ”๋ชจ๋ฆฌ์˜ ๋†’์€ ์ฃผ์†Œ์—์„œ ๋‚ฎ์€ ์ฃผ์†Œ ๋ฐฉํ–ฅ์œผ๋กœ ํ• ๋‹น๋œ๋‹ค.
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ํฌ๊ธฐ๊ฐ€ ๊ฒฐ์ •๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌดํ•œํžˆ ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค -> Stack Overflow

Heap

  • ๋Ÿฐํƒ€์ž„์— ํฌ๊ธฐ๊ฐ€ ๊ฒฐ์ •๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด๋‹ค.
  • ์‚ฌ์šฉ์ž์— ์˜ํ•ด ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ๋™์ ์œผ๋กœ ํ• ๋‹น๋˜๊ณ  ํ•ด์ œ๋œ๋‹ค
  • ์ฐธ์กฐํ˜•์˜ ๋ฐ์ดํ„ฐ์˜ ๊ฐ’์ด ์ €์žฅ๋œ๋‹ค. (์ธ์Šคํ„ด์Šค์˜ ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜๋Š” ๊ณต๊ฐ„)
  • Heap์€ ๋ฉ”๋ชจ๋ฆฌ์˜ ๋‚ฎ์€์ฃผ์†Œ ๋ถ€ํ„ฐ ๋†’์€ ์ฃผ์†Œ ๋ฐฉํ–ฅ์œผ๋กœ ํ• ๋‹น๋œ๋‹ค.

HEAP, STACK ์˜์—ญ์€ ๊ฐ™์€ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๊ณ  ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์–ด๋Š ํ•œ์ชฝ์˜ ์˜์—ญ์ด ์ƒ๋Œ€๊ณต๊ฐ„์„ ์นจ๋ฒ”ํ•˜๋Š” ์ผ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๊ณ  ์ด๋ฅผ Heap Overflow, Stack Overflow ๋ผ๊ณ  ํ•œ๋‹ค.

๊ธฐ์กด์˜ ์ง€์‹๊ณผ ์กฐ๊ธˆ ์—ฎ์–ด์„œ ํ’€์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1 ) ์ฝ”๋”ฉํ…Œ์ŠคํŠธ ๋ฌธ์ œ๋ฅผ ํ’€ ๋•Œ, ๊ฒช๋˜ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผ

๋ณดํ†ต ๋ฐฑ์ค€์—์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ๋ฅผ ํ’€ ๋‹ค ๋ณด๋ฉด ์‹ฌ์‹ฌ์ฐฎ๊ฒŒ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผ๋ฅผ ๊ฒฝํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์‹ค์ œ๋กœ ๋ฌธ์ œ์—์„œ ์š”๊ตฌํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ณด๋‹ค ๋” ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„ ์ง€์—ญ๋ณ€์ˆ˜๋กœ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ „์—ญ๋ณ€์ˆ˜๋กœ ์ˆ˜์ •ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” ๋ณดํ†ต OS์—์„œ ์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ Stack ์˜์—ญ์— ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์„ ๊ฑธ์–ด๋‘๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. (์œˆ๋„์šฐ: 1MB, ๋ฆฌ๋ˆ…์Šค: 8MB)
๋”ฐ๋ผ์„œ ์ „์—ญ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•œ ๋ฐ์ดํ„ฐ๋“ค์€ Data ์˜์—ญ์— ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

2) ARC

Swift์—์„œ๋Š” ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ

  • ์‹ค์ œ ์ธ์Šคํ„ด์Šค ๋ฉ”๋ชจ๋ฆฌ๋Š” Heap ์˜์—ญ
  • ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ๊ฐ’์€ Stack ์˜์—ญ

์— ์ €์žฅ๋˜๊ณ  RC๊ฐ€ 0์ด๋˜๋Š” ์ˆœ๊ฐ„์— ์ž๋™์œผ๋กœ Heap ์˜์—ญ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๋Š” ARC ๋ผ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

C์–ธ์–ด์˜ ๊ฒฝ์šฐ, Heap ์˜์—ญ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Calloc, Malloc๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ ํฌ๊ธฐ ๋งŒํผ์„ Heap ์˜์—ญ์— ํ• ๋‹นํ•˜๊ณ  Stack ์˜์—ญ์—๋Š” ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฃผ์†Œ๊ฐ’๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ C์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Swift์™€ ๋‹ฌ๋ฆฌ Heap์˜์—ญ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๋ฅผ ์œ„ํ•ด์„œ free ํ•ด์ฃผ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋”ฅ๋งํฌ - 01

๋”ฅ๋งํฌ

ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ค‘ FCM์„ ์ด์šฉํ•ด ๋‚ ๋ผ์˜จ ํ‘ธ์‹œ๋ฅผ ํด๋ฆญ ํ–ˆ์„ ๋•Œ ๊ด€๋ จ ๋‚ด์šฉ์„ ์•ฑ ๋‚ด์—์„œ ํ™”๋ฉด์ „ํ™˜ ํ•ด์„œ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ํ•„์š”ํ–ˆ๋‹ค. (ex ์นด์นด์˜คํ†ก ํ‘ธ์‹œ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ํ•ด๋‹น ๋Œ€ํ™”๋ฐฉ์œผ๋กœ ์ด๋™)

์ด๋Ÿฐ ๊ธฐ๋Šฅ๋“ฑ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋”ฅ๋งํฌ, ์•ฑ๋งํฌ, ์œ ๋‹ˆ๋ฒ„์…œ ๋งํฌ ๋“ฑ๋“ฑ์„ ๋“ค์–ด๋ณด๊ธด ํ–ˆ์ง€๋งŒ ํ•œ๋ฒˆ๋„ ๊ตฌํ˜„ํ•ด๋ณธ์ ์€ ์—†์–ด์„œ ์ด๋ฒˆ๊ธฐํšŒ์— ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค. SwiftUI๋ฅผ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ œ์•ฝ์‚ฌํ•ญ์ด ์žˆ์–ด ์•„์‰ฝ๊ธด ํ•˜์ง€๋งŒ ๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด UIKit์„ ์ด์šฉํ•œ ํ”„๋กœ์ ํŠธ์—๋„ ์ •๋ฆฌํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณผ ์˜ˆ์ •์ด๋‹ค.

์šฉ์–ด์ •๋ฆฌ ๋ถ€ํ„ฐ ํ•˜๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž

๋”ฅ๋งํฌ

ํŠน์ • ์ฃผ์†Œ ํ˜น์€ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด ์•ฑ์ด ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ์•ฑ ๋‚ด ํŠน์ • ํ™”๋ฉด์œผ๋กœ ์ด๋™์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰

์šฐ์„  ๋”ฅ๋งํฌ, ์•ฑ๋งํฌ, ์œ ๋‹ˆ๋ฒ„์…œ๋งํฌ๋ฅผ ๊ฐ๊ฐ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ๋”ฅ๋งํฌ๋ผ๋Š” ํฐ ๋ฒ”์ฃผ์•ˆ์—์„œ ์•ฑ๋งํฌ, ์œ ๋‹ˆ๋ฒ„์…œ ๋งํฌ๋กœ ๋‚˜๋ˆ„์–ด์ง„๋‹ค. (๋‹ค์ด๋‚˜๋ฏน ๋งํฌ, deferred ๋”ฅ๋งํฌ๋Š” ์ถ”ํ›„ ์ •๋ฆฌ)

Untitled

๊ทธ๋ฆผ์œผ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํŠน์ • ๋งํฌ๋ฅผ ์ž…๋ ฅ(ํด๋ฆญ) ํ–ˆ์„ ๋•Œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ํŽ˜์ด์ง€๋กœ ์‚ฌ์šฉ์ž๋“ค์„ ์•ˆ๋‚ดํ•˜๋Š” ๊ธฐ์ˆ ์„ ๋”ฅ๋งํฌ๋ผ๊ณ  ํ•˜๊ณ , ๋”ฅ๋งํฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์œ„์™€ ๊ฐ™์ด ์กด์žฌํ•œ๋‹ค.

(์•ฑ๋งํฌ๋Š” AOS์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์šฉ์–ด)

1) URL Scheme

์ผ๋ฐ˜์ ์ด๊ณ  ์ดˆ๊ธฐ์— ์‚ฌ์šฉ๋œ ๋”ฅ๋งํฌ ๊ตฌํ˜„ ๋ฐฉ์‹์œผ๋กœ ์•ฑ์— ์Šคํ‚ด๊ฐ’์„ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

{ Scheme : ์•ฑ์„ ๊ตฌ๋ถ„ }:// { Path : ์•ฑ๋‚ด ํŽ˜์ด์ง€ ๊ตฌ๋ถ„ }

kakaotalk://me
sms://

์œ„์˜ ๋งํฌ๋ฅผ ์‚ฌํŒŒ๋ฆฌ์— ์ž…๋ ฅํ•ด๋ณด์ž. ์นด์นด์˜คํ†ก์ด ์„ค์น˜๋˜์–ด ์žˆ๋Š” ํœด๋Œ€ํฐ์ผ ๊ฒฝ์šฐ ์นด์นด์˜คํ†ก์ด ์—ด๋ฆฌ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„๊ฒƒ์ด๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์œ„์˜ ๋‚ด์šฉ์„ ํ•œ๋ฒˆ ๊ตฌํ˜„ํ•ด๋ณด์ž(์ •๋Œ€๋ฆฌ๋‹˜์˜ ๋”ฅ๋งํฌ ๊ฐ•์˜๋ฅผ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.)

์ •๋Œ€๋ฆฌ๋‹˜ ๊ฐ•์˜ ๋งํฌ](https://www.youtube.com/watch?v=kjDl_15fOEQ)

Untitled 1

์šฐ์„ , ์œ„์™€ ๊ฐ™์ด ์Šคํ‚ด์„ ๋“ฑ๋กํ•ด์ค€๋‹ค.

enum TabIdentifier: Hashable {
  case todo
  case profile
}

enum PageIdentifier: Hashable {
  case todoItem(id: UUID)
}

extension URL {
  var isDeepLink: Bool {
    return scheme == "deeplink-bran"
  }

  // ์–ด๋–ค ํƒญ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ์ธ๊ฐ€?
  var tabIdentifier: TabIdentifier? {
    guard isDeepLink else { return nil }

    // deeplink-bran:// { host }
    switch host {
    case "todo":
      return .todo
    case "profile":
      return .profile
    default:
      return nil
    }
  }

  //deeplink-bran://todo/ED7E277E-1A5E-4197-AF6D-1D9ED1BFFF9F
  var detailPage: PageIdentifier? {
    guard
      let tabIdentifier = tabIdentifier,
      pathComponents.count > 1,
      let uuid = UUID(uuidString: pathComponents[1])
    else { return nil }

    switch tabIdentifier {
    case .todo:
      return .todoItem(id: uuid)
    case .profile:
      return nil
    }
  }
}

URL์ด ๋“ค์–ด์˜จ ๊ฒฝ์šฐ { Scheme }:// { Path } ํ˜•ํƒœ์˜ URL์ธ์ง€ ํ™•์ธํ•˜๊ณ , Path๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์ ˆํ•œ ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ด์ฃผ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋Š” Scheme:// {TabIdentifier} / {PageIdentifier?} ํ˜•ํƒœ๋กœ ๋“ค์–ด์˜จ URL์—์„œ ์‚ฌ์šฉ์ž๋ฅผ ์ ์ ˆํ•œ ํŽ˜์ด์ง€์— ๋ณด๋‚ด์ฃผ๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋“ค์„ ๋ฝ‘์•„ ๋‚ผ ์ˆ˜ ์žˆ๋„๋ก extension์œผ๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ด๋‹ค.

struct TodoTabView: View {
  let todoModels: [TodoListItem] = [...]

  @State
  var selectedTab: TabIdentifier = .todo

  var body: some View {
    tabSection
      .onOpenURL { url in
        guard let tabId = url.tabIdentifier else { return }
        selectedTab = tabId
      }
  }
}

extension TodoTabView {
  @ViewBuilder
  var tabSection: some View {
    TabView(selection: $selectedTab) {
      TodoView(todoListItems: todoModels)
        .tabItem {
          Image(systemName: "tray")

          Text("TODO")
        }
        .tag(TabIdentifier.todo)

      ProfileView()
        .tabItem {
          Image(systemName: "person")

          Text("Profile")
        }
        .tag(TabIdentifier.profile)
    }
  }
}

์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ Scheme://Path ํ˜•ํƒœ์˜ URL์ด ๋“ค์–ด์™”์„ ๊ฒฝ์šฐ, ์–ด๋–ป๊ฒŒ ํ™”๋ฉด ์ „ํ™˜๋ฅผ ์ฒ˜๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ์„๊นŒ?

์ž์„ธํ•˜๊ฒŒ ๋ณด์ง„ ์•Š์•˜์ง€๋งŒ UIKit์—์„œ๋Š” SceneDelegate, AppDelegate์—์„œ ์œ„์˜ ๋‚ด์šฉ์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ณ  ์žˆ๋Š”๊ฒƒ ๊ฐ™๋‹ค. SwiftUI์—์„œ๋Š” onOpenURL์ด๋ผ๋Š” modifier๋ฅผ ํ†ตํ•ด์„œ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

Brandnew-one/Practice-SwiftUI

ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋Š” ์œ„์˜ ๊นƒํ—ˆ๋ธŒ ๋งํฌ์—์„œ ์ „์ฒด๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์œ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ URL Scheme์„ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์„ค์ •ํ•œ ํƒญ๋ฐ” & ๋„ค๋น„๊ฒŒ์ด์…˜ ํ‘ธ์‰ฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ฒ˜์Œ ๋”ฅ๋งํฌ ๊ทธ๋ฆผ์—์„œ ๊ฐœ์„  ์ด ๊ฑธ๋ฆฐ๋‹ค. URL Scheme์—๋Š” ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ ์œ ๋‹ˆ๋ฒ„์…œ ๋งํฌ๋ผ๋Š” ๊ฐœ๋…์ด ๋‚˜์˜ค๊ฒŒ ๋œ๊ฑธ๊นŒ? ์ด๋Š” ์œ„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์š”๋ฆฌ์กฐ๋ฆฌ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋‹ค ๋ณด๋ฉด ์˜์™ธ๋กœ ์‰ฝ๊ฒŒ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์•ฑ์ด ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Œ
  • ๋™์ผํ•œ Scheme์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ

์•ฑ์ด ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์ฃผ์†Œ๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Safari๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์—ด ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜์˜ค๊ณ , ๋ฒˆ๋“ค identifier๋ฅผ ๋ฐ”๊ฟ”์„œ ๋™์ผํ•œ Scheme์ด ๋™์ผํ•œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์•ฑ์„ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธ ํ•˜๋ฉด ์–ด๋–ค ์•ฑ์ด ์—ด๋ฆด ์ง€ ์šฐ๋ฆฌ๊ฐ€ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ ์ด Scheme์€ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์•ฑ์—์„œ Identifiable๋ฅผ ๋ณด์žฅ ํ•  ์ˆ˜ ์—†๋‹ค.

๋‹ค์Œ ํ† ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์œ ๋‹ˆ๋ฒ„์…œ ๋งํฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์ •๋ฆฌํ•ด๋ณผ ์˜ˆ์ •์ด๋‹ค.

[WKWebView] Dynamic Height in SwiftUI

WKWebView Dynamic Height

ํ”„๋กœ์ ํŠธ ๊ตฌํ˜„์‚ฌํ•ญ ์ค‘ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ›์€ html์„ WebView๋ฅผ ํ†ตํ•ด์„œ ๋ณด์—ฌ์ค˜์•ผํ–ˆ๋Š”๋ฐ ์ด๋•Œ ๊ฒช์—ˆ๋˜ ์ด์Šˆ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ WKWebView๋ฅผ SwiftUI์—์„œ ์ œ๊ณตํ•ด์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— UIViewRepresentable ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ์„  UIKit์œผ๋กœ ๋จผ์ € ๊ตฌํ˜„ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

import UIKit
import WebKit

class ViewController: UIViewController {
  let webView = WKWebView()

  override func viewDidLoad() {
    super.viewDidLoad()
    setupView()
    setupConstraints()
    setupWebView()
  }

  func setupView() {
    webView.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .white
    view.addSubview(webView)
  }

  func setupConstraints() {
    NSLayoutConstraint.activate([
      webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
      webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
      webView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
    ])
  }

  func setupWebView() {
    let testHTML =
    """
    ... HTML ...
    """
    webView.navigationDelegate = self
    webView.loadHTMLString(testHTML, baseURL: nil)
  }
}

์œ„์™€ ๊ฐ™์ด webView์˜ height constraints๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š๊ณ , html์„ ๋กœ๋“œํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?
์‚ฌ์‹ค ์ฒ˜์Œ์—๋Š” top, leading, trailing constraints๋งŒ ์„ค์ •ํ•ด์ฃผ๋ฉด height์€ webView์—์„œ loadํ•œ html์„ ์ž๋™์œผ๋กœ ๋จน์ง€ ์•Š์„๊นŒ? ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์–ด๋ฆผ๋„ ์—†์—ˆ๋‹ค.

์‹ค์ œ๋กœ ์ฒ˜์Œ์— webView์— height์„ ์„ค์ •ํ•˜๋ฉด ํ•ด๋‹น ํฌ๊ธฐ ๋งŒํผ์˜ WebView๋งŒ ์ƒ์„ฑ๋˜๊ณ  ๋งŒ์•ฝ ์‹ค์ œ load๋˜๋Š” html์ด ํ•ด๋‹น ํฌ๊ธฐ๋ณด๋‹ค ํฌ๋‹ค๋ฉด ์Šคํฌ๋กค ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์Šคํฌ๋กค ์—†์ด html์ด load ๋˜๋Š” ์ˆœ๊ฐ„์— ๋†’์ด๋ฅผ ๊ณ„์‚ฐํ•ด์„œ dynamic ํ•˜๊ฒŒ height์„ ์„ค์ •ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

๊ฒฐ๋ก  ๋ถ€ํ„ฐ ์–˜๊ธฐํ•˜์ž๋ฉด, WKWebView Delegate ์ค‘ ์ •ํ™•ํ•˜๊ฒŒ html์ด load๋˜๋Š” ์‹œ์ ์— ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

WKWebView์ด์ „์˜ UIWebView์—๋Š” webViewDidFinishLoad๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€๋Šฅํ–ˆ์ง€๋งŒ ์–ด์งธ์„œ ์ธ์ง€ WKWebView์—๋Š” ์—†๋‹ค...

๊ทธ๋ž˜๋„ ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์—์„œ ์–ด๋–ป๊ฒŒ๋“  ๊ตฌํ˜„ํ•œ ์‚ฌ๋žŒ๋“ค์˜ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด์„œ ์•ผ๋งค(?)๋กœ๋ผ๋„ ์ด๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.
์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ
์—์„œ ์ œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

  • DispatchQueue.main.asyncAfter
  • evaluateJavaScript(""document.readyState")

์š”์•ฝํ•˜๋ฉด WKNavigationDelegate์— ์กด์žฌํ•˜๋Š” didFinish ์‹œ์ ์— + ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด scrollView์˜ content height์„ ๊ณ„์‚ฐํ•ด ์ด๋ฅผ webView์˜ height์œผ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์‚ฌ์‹ค ๋‘๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ js๋ฅผ ์ž˜ ๋ชจ๋ฅด๋Š” ๋‚˜๋กœ์„œ๋Š” ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ •ํ™•ํžˆ ์–ด๋–ค ์‹œ์ ์— ํ˜ธ์ถœ๋˜๋Š”์ง€ ๋ชฐ๋ผ ์ •ํ™•ํ•œ ๋ฐฉ๋ฒ•์ธ์ง€ ์•„์ง ํŒ๋‹จ์„ ํ•˜์ง€ ๋ชปํ–ˆ๊ณ ,
์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ didFinish๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์œผ๋กœ ๋ถ€ํ„ฐ n์ดˆ ํ›„์—๋Š” html load๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์„ ๊ฒƒ์ด๋ผ๋Š” ๋ง‰์—ฐํ•œ ๋ฏฟ์Œ์„ ๊ฐ€์ง€๊ณ  ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ์ธ์ ์œผ๋กœ ๋‘ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. (๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ๊ฒŒ ๋˜๋ฉด ๋‹ค์‹œ ๋˜ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.)

extension ViewController: WKNavigationDelegate {
  func webView(
    _ webView: WKWebView,
    didFinish navigation: WKNavigation!
  ) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
      guard let self = self else { return }
      NSLayoutConstraint.activate([
        self.webView.heightAnchor.constraint(equalToConstant: self.webView.scrollView.contentSize.height)
      ])
    }
  }
}

์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋ฉด ์œ„์™€ ๊ฐ™๋‹ค. (0.3์ดˆ ์•ˆ์— load๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š๋Š” case๋Š” ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์—†๋‹ค)

์œ„์˜ WebView๋ฅผ SwiftUI์—์„œ ๊ตฌํ˜„ํ•ด๋ณด์ž

struct HtmlView: UIViewRepresentable {
  let htmlContent: String
  let webView = WKWebView()

  @ObservedObject
  var viewModel: HTMLStringViewModel

  func makeUIView(context: Context) -> WKWebView {
    webView.scrollView.isScrollEnabled = false
    webView.scrollView.panGestureRecognizer.isEnabled = false
    webView.scrollView.delegate = context.coordinator
    webView.navigationDelegate = context.coordinator
    webView.isUserInteractionEnabled = false
    webView.loadHTMLString(htmlContent, baseURL: nil)
    return webView
  }

  func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<HtmlView>) {
    guard context.coordinator.webView == nil else { return }
    context.coordinator.webView = uiView
  }

  func makeCoordinator() -> Coordinator {
    Coordinator(parent: self)
  }

  class Coordinator: NSObject {
    var webView: WKWebView?
    var parent: HtmlView

    init(parent: HtmlView) {
      self.parent = parent
    }
  }
}

extension HtmlView.Coordinator: UIScrollViewDelegate {
  func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return nil
  }
}

extension HtmlView.Coordinator: WKNavigationDelegate {
  func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
      guard let self = self else { return }
      self.parent.viewModel.heightSubject.send(webView.scrollView.contentSize.height)
    }
  }
}

final class HtmlViewModel: ObservableObject {
  let heightSubject: PassthroughSubject<CGFloat, Never>

  init(_ sub: PassthroughSubject<CGFloat, Never>) {
    self.heightSubject = sub
  }
}

SwiftUI์—์„œ๋Š” View๊ฐ€ ๊ตฌ์กฐ์ฒด ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— Delegate ํŒจํ„ด์„ Coordinator๋ฅผ ํ†ตํ•ด ์ฑ„ํƒํ•œ๋‹ค๋Š” ๊ฒƒ๋งŒ ์ œ์™ธํ•˜๋ฉด ๊ธฐ๋ณธ์ ์ธ ๊ตฌํ˜„๊ณผ์ •์€ ์‚ฌ์‹ค UIKit๊ณผ ์™„์ „ํžˆ ๋™์ผํ•˜๋‹ค.

์œ„์˜ ๋‚ด์šฉ์„ ๊ตฌํ˜„ํ•  ๋•Œ, HtmlView๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ถ€๋ถ„์—์„œ .frame() modifier๋ฅผ ํ†ตํ•ด์„œ ๋†’์ด๋ฅผ dynamicํ•˜๊ฒŒ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ Subject๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
๋ง๋กœ๋งŒ ์„ค๋ช…ํ•˜๋ฉด ๋˜๊ฒŒ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ํ™•์ธํ•ด๋ณด์ž

// View ๋‚ด๋ถ€
HtmlView(
  htmlContent: ---html---,
  viewModel: HtmlViewModel(viewModel.input.---sub)
)
.frame(height: viewModel.output.testHeight)
// View์˜ ViewModel ๋‚ด๋ถ€
input.--tSub
      .sink(receiveValue: { [weak self] in
        guard let self = self else { return }
        self.output.testHeight = $0
      })
      .store(in: &cancellables)

์ •๋ฆฌํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. HtmlView๋ฅผ ์‚ฌ์šฉํ•˜๋Š” View์˜ ViewModel์—์„œ subject๋ฅผ HtmlViewModel๋กœ subject๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.
  2. HtmlView์˜ Coordinator์—์„œ HtmlViewModel์˜ subject๋กœ load๋œ html์˜ ๋†’์ด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.
  3. View์˜ ViewModel์—์„œ subject๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ’์ด ๋“ค์–ด์˜ค๋ฉด @published output ๊ฐ’์œผ๋กœ dynamicํ•œ height์„ ๋„˜๊ฒจ์ฃผ๊ณ , View๋Š” ์ด ๊ฐ’์„ ํ†ตํ•ด View๋ฅผ re-rendering ํ•œ๋‹ค.

์—ฌ์ „ํžˆ n์ดˆ ์ด๋‚ด์— html์ด load ๋˜์ง€ ์•Š๋Š” webView์— ๋Œ€ํ•ด์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋‹ค๋Š” ํฐ ๋ฌธ์ œ๊ฐ€ ๋‚จ์•„ ์žˆ์ง€๋งŒ, ํ•ด๋‹น ์ผ€์ด์Šค๋ฅผ ์ œ์™ธํ•˜๋ฉด ๋ชจ๋‘ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ webView๊ฐ€ ๊ทธ๋ฆฌ๋Š” ์˜์—ญ์ด ๊ต‰์žฅํžˆ ์ž‘๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜์ง„ ์•Š์ง€๋งŒ ์–ธ์ œ๋“ ์ง€ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.)

์šฐ์„ , ์œ„์™€ ๊ฐ™์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋Š”๋ฐ ์—ฌ์ „ํžˆ ์ฐ์ฐํ•œ ๋ถ€๋ถ„๋“ค์ด ๋‚จ์•„์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง๊นŒ์ง€ ์™„๋ฒฝํ•œ ๋ฐฉ๋ฒ•์€ ์ฐพ์ง€ ๋ชปํ•œ ์ƒํƒœ์ด๋‹ค ใ… 
ํ˜น์‹œ๋ผ๋„ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋– ์˜ค๋ฅด๊ฑฐ๋‚˜ ์ฐพ๊ฒŒ ๋˜๋ฉด ๋‹ค์‹œ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค

์ด ๊ธ€์„ ๋ณด๋‹ค ๋” ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ์‹  ๋ถ„๋“ค์€ [email protected]์œผ๋กœ ์—ฐ๋ฝ์ฃผ์‹œ๋ฉด ์ •๋ง ์ง„์งœ ์ •๋ง ์ง„์งœ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

[SwiftUI] TextField, SecureField in Alert

Link ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋“ฏ์ด ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ UIKit์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ํ…์ŠคํŠธํ•„๋“œ๊ฐ€ ์žˆ๋Š” AlertView๋ฅผ SwiftUI์—์„œ๋Š” 16.0 ๋ฏธ๋งŒ์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค

  1. UIViewControllerRepresentable์„ ์ด์šฉ (๋ž‘ํฌ)
  2. SwiftUI 4.0 ์‚ฌ์šฉ (ํ…Œ์ŠคํŠธ ์˜ˆ์ •)

RSA - 1

RSA

RSA๋„ ์ง€๋‚œ๋ฒˆ์— ํ™•์ธํ–ˆ๋˜ ECDSA์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”์˜ ํ•œ ์œ ํ˜•์ด๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์•”ํ˜ธํ™”์™€ ๋””์ง€ํ„ธ ์„œ๋ช…์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š”๋ฐ ECDSA๋ฅผ ํ†ตํ•ด์„œ ๋””์ง€ํ„ธ ์„œ๋ช…๊ณผ์ •์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒˆ์—๋Š” RSA๋ฅผ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”, ๋ณตํ˜ธํ™” ๊ณผ์ •์„ ํ•œ๋ฒˆ ๊ตฌํ˜„ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

  • Private Key, Public Key ์ƒ์„ฑ
  • Public Key๋ฅผ ํ†ตํ•œ ์•”ํ˜ธํ™”
  • Private Key๋ฅผ ํ†ตํ•œ ๋ณตํ˜ธํ™”

์ˆœ์„œ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค


1) Key Pair ์ƒ์„ฑ

RSA๊ฐ€ ๋ญ”์ง€๋„ ๋ชจ๋ฅด๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋‚˜์š”?

ECDSA์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์• ํ”Œ์—์„œ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”์— ๋Œ€ํ•œ ํŠน์„ฑ๋งŒ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์ „ํ˜€ ๋ฌธ์ œ์—†๋‹ค.

import Foundation

final class RSA {
  private var privateKey: SecKey?
  private var publicKey: SecKey?
  private let dataStorage: KeyChainDataStorage

  init(
    dataStorage: KeyChainDataStorage
  ) {
    self.dataStorage = dataStorage
    if let privateKey = dataStorage.read(key: .rsa),
       let secKey = stringToSecKey(privateKey) {
      print("From KeyChain")
      self.privateKey = secKey
      self.publicKey = SecKeyCopyPublicKey(secKey)
    } else {
      print("From New")
      generateRSAKeyPair()
      saveRSAKey()
    }
  }

  // FIXME: -  Key Representation์„ ์„ค์ •ํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ์ 
  private func generateRSAKeyPair() {
    var error: Unmanaged<CFError>?
    let parameters: [CFString: Any] = [
      kSecAttrKeyType: kSecAttrKeyTypeRSA,
      kSecAttrKeySizeInBits: 2048,
      kSecAttrKeyClass: kSecAttrKeyClassPrivate
    ]
    guard
      let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error),
      let publicKey = SecKeyCopyPublicKey(privateKey)
    else { return }

    self.privateKey = privateKey
    self.publicKey = publicKey
  }
}

KeyChainDataStorage๋Š” ์ถ”ํ›„ ํ‚ค์ฒด์ธ ์ €์žฅ์—์„œ ๋‹ค๋ฃจ๊ธฐ๋กœ ํ•˜๊ณ  ํ‚ค ์ƒ์„ฑ์—์„œ ํ™•์ธํ•ด์•ผ ํ•  ๋ถ€๋ถ„์€

  • ECDSA์™€ ๋‹ฌ๋ฆฌ CryptoKit์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค
  • Key์˜ ํƒ€์ž…์ด SecKey ํƒ€์ž…์ด๋‹ค
  • CFError, CFString, CFDictionary ๋“ฑ๋“ฑ์˜ ํƒ€์ž…๋“ค์€ ๋ฌด์—‡์ผ๊นŒ?

ECDSA ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์˜ ๊ฒฝ์šฐ, CryptoKit์„ ์ด์šฉํ–ˆ์ง€๋งŒ RSA๋Š” Security๋ฅผ ์ด์šฉํ•œ๋‹ค.

SecKey ํƒ€์ž…๋„ Security์— ์ •์˜๋œ ํด๋ž˜์Šค๋กœ ์ •ํ™•ํ•œ ๊ตฌํ˜„์ฒด๋Š” ํ™•์ธํ•  ์ˆ˜ ์—†์ง€๋งŒ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ณ  ์ด๋ฅผ ์ด์šฉํ•ด์„œ ์•”ํ˜ธํ™”, ๋ณตํ˜ธํ™”, ์„œ๋ช…๋“ค์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ๋“ค์— CF๊ฐ€ ๋ถ™์€ ํƒ€์ž…๋“ค์ด ๋งŽ์€๋ฐ Core Foundation์—์„œ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ Swift Type๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํƒ€์ž… ์บ์ŠคํŒ…์ด ํ•„์š”ํ•˜๋‹ค

ํ‚ค ์ƒ์„ฑ ๊ณผ์ •์„ ํ™•์ธํ•ด๋ณด๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” RSA Private Key ์ŠคํŽ™์„ CFDictionary์— ๋‹ด์•„์„œ Private Key๋ฅผ ๋งŒ๋“ค๊ณ  Private Key๋ฅผ ํ†ตํ•ด์„œ Public Key๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


ECDSA ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ํ‚ค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, Representation์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ RSA์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ• ๊นŒ?

๊ณต์‹ ํ™ˆํŽ˜์ด์ง€๋ž‘ ์Šคํƒ์˜ค๋ฒ„ ํ”Œ๋กœ์šฐ๋ฅผ ๋งŽ์ด ๋’ค์กŒ์ง€๋งŒ ์ƒ์„ฑํ•˜๋Š” ์‹œ์ ์— Representation์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋”ฐ๋กœ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค.
์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐพ์œผ๋ฉด ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

์‚ฌ์‹ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋‹จ์ˆœ ๊ตฌํ˜„ ๋ณด๋‹ค๋Š” ์„œ๋ฒ„์™€ ์ŠคํŽ™์„ ๋งž์ถ”๋Š” ๊ณผ์ •์ด ์ค‘์š”ํ•œ๋ฐ ์ƒ์„ฑ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ•ด์„œ ๊ฐœ์ธ์ ์œผ๋กœ ๊ต‰์žฅํžˆ ์•„์‰ฌ์› ๋‹ค.

https://github.com/TakeScoop/SwiftyRSA

์œ„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Representation ์„ค์ •๋ฟ๋งŒ ์•„๋‹ˆ๋ผ encrypt/decrypt ๊ณผ์ •์— swift์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ํŒจ๋”ฉ ๋ชจ๋“œ๋“ค๋„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์œผ๋‹ˆ ํ•„์š”์— ๋”ฐ๋ผ์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 6

HTTP ์ƒํƒœ์ฝ”๋“œ

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ๋ณด๋‚ธ ์š”์ฒญ์˜ ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด 5๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

  • 1xx (Informational)
  • 2xx (Successful)
  • 3xx (Redirection)
  • 4xx (Client Error)
  • 5xx (Server Error)

(1xx๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žต)


2xx - ์„ฑ๊ณต

200 OK

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ๋ณด๋‚ธ ์š”์ฒญ์„ ์„ฑ๊ณตํ•ด์„œ ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด์ค„ ๋•Œ์˜ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์˜๋ฏธ

201 Created

์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋˜์–ด์„œ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Œ์„ ์˜๋ฏธ

POST๋ฅผ ํ†ตํ•ด์„œ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๋ฅผ DB์— ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ฐ€์ •ํ•ด๋ณด์ž.

PUT๊ณผ ๋‹ฌ๋ฆฌ POST๋ฅผ ํ†ตํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฆฌ์†Œ์Šค์˜ URI๋ฅผ ๋ชจ๋ฅธ๋‹ค. ์ด๋•Œ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์˜ URI๋ฅผ ์‘๋‹ต์˜ ํ—ค๋”์— (Location)์— ์‹ค์–ด์„œ ๋ณด๋‚ด์ค€๋‹ค.

202 Accepted

์š”์ฒญ์ด ์ ‘์ˆ˜๋˜์—ˆ์œผ๋‚˜ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ์ƒํƒœ

  • ๋ฐฐ์น˜์ฒ˜๋ฆฌ์—์„œ ์‚ฌ์šฉ

204 No Content

์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ, ํด๋ผ์ด์–ธํŠธ์— ๋ณด๋‚ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Œ

์•ฑ์—์„œ ์œ ์ €๊ฐ€ ๊ฒŒ์‹œ๊ธ€์„ ์ˆ˜์ •ํ•˜๊ณ  ์ €์žฅ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. PUT, POST, PATCH ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •์„ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ๋ฐ›๊ณ  ํ•ด๋‹น ์ž‘์—…์„ ์™„๋ฃŒ ๋˜์—ˆ์Œ์„ ํ‘œํ˜„ํ•  ๋•Œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ค˜์•ผํ• ๊นŒ?

200 OK์— ์„ฑ๊ณตํ–ˆ์Œ์„ ์˜๋ฏธํ•˜๋Š” ํ‘œํ˜„์„ ๋‹ด์•„์„œ ๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ ์‚ฌ์‹ค ์„ฑ๊ณตํ–ˆ์Œ๋ผ๋Š” ์—ฌ๋ถ€๋งŒ ํ•„์š”ํ•œ ๊ฒƒ์ด์ง€ ์–ด๋– ํ•œ ๋ฐ์ดํ„ฐ๋„ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์— 204 No Content๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์‚ฌ์‹ค ํด๋ผ์ด์–ธํŠธ ๊ฐœ๋ฐœ ์ž…์žฅ์—์„œ๋Š” ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ 200, 204๋“  ์ƒ๊ด€์—†์ด Response Body๊ฐ’์„ ๋””์ฝ”๋”ฉํ•˜๋Š” ๊ณผ์ •์—†์ด ์ƒํƒœ์ฝ”๋“œ๋งŒ์„ ์ด์šฉํ•ด์„œ ์œ ์ €์—๊ฒŒ ์„ฑ๊ณต, ์‹คํŒจ ์—ฌ๋ถ€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋ฉด ๋ ๊ฒƒ ๊ฐ™์€๋ฐ 204๋ผ๋Š” ์ƒํƒœ์ฝ”๋“œ์˜ ์˜๋ฏธ๋ฅผ ํ†ตํ•ด์„œ ๋” ๋ช…ํ™•ํžˆ ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.


3xx - ๋ฆฌ๋‹ค์ด๋ ‰์…˜

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์š”์ฒญ์„ ์™„๋ฃŒํ•˜๊ธฐ ์œ„ํ•ด์„œ ์œ ์ € ์—์ด์ „ํŠธ(์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜)์˜ ์ถ”๊ฐ€ ์กฐ์น˜ ํ•„์š”๋ฅผ ์˜๋ฏธ

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ(Re-Direct)

๋‹จ์–ด์˜๋ฏธ ๊ทธ๋Œ€๋กœ ๋‹ค์‹œ ๋ฐฉํ–ฅ์„ ๊ฐ€๋ฆฌํ‚ค๋Š”๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์›น ๋ธŒ๋ผ์šฐ์ €๋Š” 3xx ์‘๋‹ต์˜ ๊ฒฐ๊ณผ์— Location ํ—ค๋”๊ฐ€ ์žˆ์œผ๋ฉด Location ์œ„์น˜๋กœ ์ž๋™ ์ด๋™ํ•œ๋‹ค.

Untitled

์ถœ์„ ์ด๋ฒคํŠธ ํŽ˜์ด์ง€๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. ์œ ์ €๊ฐ€ ๋งŒ์•ฝ ๋ถ๋งˆํฌ๋œ ์ด์ „์˜ ์ด๋ฒคํŠธ ํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐ”์„ ๊ฒฝ์šฐ ์„œ๋ฒ„์—์„œ 300๋ฒˆ๋Œ€ ์ƒ๋Œ€์ฝ”๋“œ์™€ ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ํŽ˜์ด์ง€๋ฅผ ๋ณด๋‚ด์ฃผ๊ณ  ์œ ์ €์˜ URL์„ ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‹œํ‚จ๋‹ค.

Untitled 1

์˜๊ตฌ ๋ฆฌ๋‹ค์ด๋ ‰์…˜

301 Moved Permanently

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œ ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ GET์œผ๋กœ ๋ณ€ํ•˜๊ณ  ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๊ฐ€ ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ์Œ

ํ•ญ์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ณ€ํ•˜๊ณ  ๋ณธ๋ฌธ์ด ์ œ๊ฑฐ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„ ํ•ด๋‹น ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

308 Permanet Redirect

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œ ์š”์ฒญ ๋ฉ”์„œ๋“œ์™€ ๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ์œ ์ง€

๋‘˜์˜ ์ฐจ์ด๋ฅผ ์ด์ „๊ณผ ๋™์ผํ•œ ํ™˜๊ฒฝ์—์„œ ์œ ์ €๊ฐ€ ํŠน์ • ์ด๋ฒคํŠธ ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ด์„œ ํ™•์ธ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ๋ฅผ ์˜ˆ์‹œ๋กœ ๋“ค์–ด๋ณด์ž.

// MARK: - 301

// ์œ ์ € ์š”์ฒญ - URL:/event
POST /event HTTP/1.1

name=hello&age=20

// ์‘๋‹ต
HTTP/1.1 301 Moved Permanently
Location: /new-event

// ์œ ์ € ์š”์ฒญ - URL:/event-new
GET /new-event HTTP/1.1
// MARK: - 308

// ์œ ์ € ์š”์ฒญ - URL:/event
POST /event HTTP/1.1

name=hello&age=20

// ์‘๋‹ต
HTTP/1.1 301 Moved Permanently
Location: /new-event

// ์œ ์ € ์š”์ฒญ - URL:/event-new
POST /event HTTP/1.1

name=hello&age=20

301์˜ ๊ฒฝ์šฐ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ดํ›„ ์š”์ฒญํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ GET์œผ๋กœ ๋ฐ”๋€Œ๊ณ  ๋ฉ”์‹œ์ง€๊ฐ€ ์‚ฌ๋ผ์ง„๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ ์ƒˆ๋กญ๊ฒŒ ๋ฆฌ๋‹ค์ด๋ ‰์…˜๋œ ํŽ˜์ด์ง€์—์„œ ๋‹ค์‹œ ์ด๋ฒคํŠธ๋ฅผ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  POST๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค.

์ผ์‹œ์ ์ธ ๋ฆฌ๋‹ค์ด๋ ‰์…˜

302 Found

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œ ๋ฉ”์„œ๋“œ๊ฐ€ GET์œผ๋กœ ๋ณ€ํ•˜๊ณ  ๋ณธ๋ฌธ์ด ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ์Œ (301๊ณผ ์œ ์‚ฌ)

307 Temporary Redirect

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œ ์š”์ฒญ ๋ฉ”์„œ๋“œ์™€ ๋ณธ๋ฌธ ์œ ์ง€

303

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์‹œ ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ GET์œผ๋กœ ๋ณ€๊ฒฝ

307, 303์€ 301๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ŠคํŽ™์ƒ์œผ๋กœ๋Š” ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€๋Š” ์•Š์ง€๋งŒ ๊ฑฐ์˜ ๋ชจ๋“  ์›น ๋ธŒ๋ผ์šฐ์ €๋“ค์ด GET์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ชจํ˜ธํ•จ์„ ์—†์• ๊ธฐ ์œ„ํ•ด์„œ ์ŠคํŽ™์ƒ ํ™•์‹คํžˆ ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ”๋€Œ๋Š” 303, ๊ทธ๋ ‡์ง€ ์•Š์€ 307์ด ๋“ฑ์žฅํ–ˆ๋‹ค.

๊ทธ๋Ÿผ ์˜๊ตฌ์ ์ธ ๋ฆฌ๋‹ค์ด๋ ‰์…˜๊ณผ ์ผ์‹œ์ ์ธ ๋ฆฌ๋‹ค์ด๋ ‰์…˜์˜ ์ฐจ์ด์ ์ด ๋ฌด์—‡์ผ๊นŒ?

๋ฆฌ์†Œ์Šค์˜ URI๊ฐ€ ์˜๊ตฌ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ์ผ์‹œ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š”์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆ ์ง„๋‹ค. ํ•˜์ง€๋งŒ ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ ๋ณ€๊ฒฝ๋œ URI๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ๋˜๋Š” ๊ฒฐ๊ณผ๋Š” ๊ฐ™์€๋ฐ ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”๊ฑธ๊นŒ?

๊ฒฐ๋ก ์ ์œผ๋กœ ๋งํ•˜๋ฉด ์ด ๋‘˜์„ ๊ตฌ๋ณ„ํ•˜๋Š” ์ฃผ์ฒด๋Š” ์‚ฌ๋žŒ์ด ์•„๋‹ˆ๋ผ ๊ฒ€์ƒ‰์—”์ง„์ด๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์ฐจ์ด๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค.

์˜๊ตฌ ๋‹ค์ด๋ ‰์…˜์ธ ๊ฒฝ์šฐ์—๋Š” ๊ฒ€์ƒ‰์—”์ง„์—์„œ๋„ URL์ด ๋ณ€๊ฒฝ๋˜๊ณ  ์ผ์‹œ์ ์ธ ๋‹ค์ด๋ ‰์…˜์—์„œ๋Š” ๊ฒ€์ƒ‰์—”์ง„์—์„œ๋Š” URL์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

๐ŸŒ 301 vs 302 ์ƒํƒœ ์ฝ”๋“œ ์ฐจ์ด์  (SEO)

์œ„์˜ ๋ธ”๋กœ๊ทธ์—์„œ๋Š” ์บ์‹ฑ์— ๋Œ€ํ•œ ์ฐจ์ด๋„ ์žˆ๋Š”๋ฐ ํ•ด๋‹น ๋ถ€๋ถ„์€ ์บ์‹ฑ์— ๋Œ€ํ•ด ์ข€ ๋” ๊ณต๋ถ€ํ•˜๊ณ  ๋‹ค์‹œ ์ •๋ฆฌ

PRG(Post Redirect Get)

์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ์š”์ฒญ์„ ๋‹ค์‹œ ๋ณด๋‚ด๊ฒŒ ๋˜๋Š”๋ฐ POST ๋ฉ”์„œ๋“œ๋กœ ์Œ์‹์„ ์ฃผ๋ฌธํ•˜๊ณ  ์ƒˆ๋กœ๊ณ ์นจ ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? โ†’ ์ค‘๋ณต ์ฃผ๋ฌธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

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


4xx - ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜

ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ์ž˜๋ชป๋˜์–ด์„œ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ

ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜์™€ ์„œ๋ฒ„์˜ค๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ธฐ์ค€์€ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋กœ ์žฌ์‹œ๋„ ์ผ์–ด๋‚ฌ์„ ๋•Œ ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜๋Š” ์ด๋ฏธ ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์†ํ•ด์„œ ์‹คํŒจํ•˜๊ณ  ์„œ๋ฒ„ ์˜ค๋ฅ˜๋Š” ์„œ๋ฒ„์˜ ์ƒํƒœ๊ฐ€ ์•ˆ์ •ํ™”(?)๋˜๋ฉด ๋ณต๊ตฌ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

400 Bad Request

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž˜๋ชป๋œ ์š”์ฒญ์„ ํ•ด์„œ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Œ

401 Unauthorized

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ธ์ฆ์ด ํ•„์š”ํ•จ

  • Authoriazation(์ธ๊ฐ€): ํŠน์ • ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ
  • Authentication(์ธ์ฆ): ๋ณธ์ธ ํ™•์ธ(๋กœ๊ทธ์ธ)

์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ Unauthorized๊ฐ€(์ธ๊ฐ€)๋กœ ๋˜์–ด์žˆ์ง€๋งŒ ์ธ์ฆ์— ๋Œ€ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋ƒ„

403 Forbidden

์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ดํ•ดํ–ˆ์ง€๋งŒ ์Šน์ธ์„ ๊ฑฐ๋ถ€ํ•จ โ†’ ์ ‘๊ทผ ๊ถŒํ•œ์ด ๋ถˆ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ

404 Not Found

์š”์ฒญ ๋ฆฌ์†Œ์Šค๊ฐ€ ์„œ๋ฒ„์— ์—†์Œ


5xx - ์„œ๋ฒ„ ์˜ค๋ฅ˜

500 Internal Server Error

์„œ๋ฒ„ ๋‚ด๋ถ€ ๋ฌธ์ œ๋กœ ์˜ค๋ฅ˜ ๋ฐœ์ƒ

์• ๋งคํ•˜๋ฉด 500๋ฒˆ ์—๋Ÿฌ๋ฅผ ์ฃผ๋Š”๋ฐ ์ด๋Š” ์ˆœ์ˆ˜ํ•œ ์„œ๋ฒ„์˜ค๋ฅ˜์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ์ง€ํ–ฅํ•ด์•ผ ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด์„œ 19์„ธ ๋ฏธ๋งŒ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์ฃผ๋ฅ˜๋ฅผ ์ฃผ๋ฌธํ–ˆ์„ ๋•Œ ์„œ๋ฒ„์—์„œ ์œ ์ €์˜ ๋‚˜์ด ๋•Œ๋ฌธ์— ์ •์ƒ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” 2xx, 4xx๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ๋‹ค.

200 vs 404

503 Service Unavailable

์„œ๋น„์Šค ์ด์šฉ ๋ถˆ๊ฐ€

์ผ์‹œ์ ์ธ ๊ณผ๋ถ€ํ•˜ ํ˜น์€ ์˜ˆ์ •๋œ ์ž‘์—…์œผ๋กœ ์„œ๋ฒ„๋ฅผ ๋‹ค์šด ์‹œ์ผœ๋†“์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๊ณ  Retry-After ํ—ค๋”๋กœ ๋ณต๊ตฌ ์‹œ๊ฐ„์„ ๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ๋‹ค.

Enum - Associated Value

enum State {
  case reday
  case stop
  case go
}

let state: State = .go

if state == .go {
  print("True")
}

์ผ๋ฐ˜์ ์œผ๋กœ ์—ด๊ฑฐํ˜•์„ ์‚ฌ์šฉํ•  ๋•Œ ์œ„์™€ ๊ฐ™์ด case๋ฅผ ์ง์ ‘ ๋น„๊ตํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฐ๊ด€๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

enum States: Equatable {
  case ready(String)
  case stop(Int)
  case go
}

let states: States = .ready("Ready")

if states == .ready("Ready") {
  print("True")
} else {
  print("False")
}

์—ฐ๊ด€๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์œ„์™€ ๊ฐ™์€ case ๋น„๊ต๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. Equtable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด ๊ฐ€๋Šฅํ•˜๊ธด ํ•ฉ๋‹ˆ๋‹ค.

if case let .ready("Ready") = states {
  print("True")
}

Xcode ๊ฐœ๋ฐœ(๋ฐฐํฌ)ํ™˜๊ฒฝ ๋‚˜๋ˆ„๊ธฐ - 1

๊ฐœ๋ฐœํ™˜๊ฒฝ ๋‚˜๋ˆ„๊ธฐ

Xcode๋ฅผ ํ†ตํ•ด์„œ ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ์™œ ๋‚˜๋ˆŒ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€์—์„œ ์„œ๋ฒ„๊ฐ€ ํ™˜๊ฒฝ๋ณ„๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋”ฐ๋กœ ๋‚˜๋ˆ ์„œ ์ž‘์—…์„ ํ•ด๋ณธ ๊ฒฝํ—˜์ด ์—†์—ˆ๋‹ค. (๋ฌผ๋ก  ๊ด‘๊ณ ๋ฅผ ๋ถ™์ด๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•„์š”ํ• ๊ฒƒ ๊ฐ™๋‹ค)

ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ํšŒ์‚ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆŒ ํ•„์š”์„ฑ์ด ์ƒ๊ธฐ๊ฒŒ ๋œ๋‹ค.

  • ์„œ๋ฒ„๊ฐ€ ํ™˜๊ฒฝ๋งˆ๋‹ค ๊ฐ’์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ ํ™˜๊ฒฝ๋งˆ๋‹ค ๋ฐฐํฌ๋ฅผ ๋‹ฌ๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํšŒ์‚ฌ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ ์„œ๋ฒ„์™€ DB๊ฐ€ dev, stage, production ์ •๋„๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๊ทธ์— ๋”ฐ๋ผ์„œ ๋‹น์—ฐํžˆ ํ™˜๊ฒฝ๋ณ„๋กœ ์„œ๋ฒ„๋ช…, ๋„๋ฉ”์ธ, IP, ์ ‘์†๊ณ„์ • ๋“ฑ ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด ๋‹ค๋ฅด๋‹ค.

๋ฐฐํฌ ๊ด€์ ์—์„œ๋„ ์ผ๋ฐ˜์ ์œผ๋กœ dev๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ณ  stage๋กœ qa์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ณ  ์ตœ์ข…์ ์œผ๋กœ prod๋กœ ๋ฐฐํฌ๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ qa์—์„œ ๋ฐœ๊ฒฌ๋œ ๋ฒ„๊ทธ๋“ค์„ ์ˆ˜์ •ํ•˜๋ฉด์„œ ๋™์ผ ๋ฒ„์ „ ๋‚ด์—์„œ ๋‹ค๋ฅธ ๋นŒ๋“œ๋ฒˆํ˜ธ๊ฐ€ ์ž‘์—…๋“ค์ด testflight์— ์Œ“์ด๊ฒŒ ๋œ๋‹ค.

์ด๋•Œ ํ™˜๊ฒฝ๋ถ„๋ฆฌ ์—†์ด ์ž‘์—…ํ•˜๋‹ค๊ฐ€ ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š” ๋ฒ„์ „์„ ๋ฐฐํฌํ•˜๊ฒŒ ๋˜๋Š” ๋‚ ์—๋Š” ์ƒ์ƒํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ์ ๋“ค์„ ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆ ์„œ ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ url์„ ๊ฐ€์ง€๋„๋ก ์„ค์ •ํ•˜๊ณ , ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ name, bundle identifier๋ฅผ ์„ค์ •ํ•จ์œผ๋กœ์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.


๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ๋‚˜๋ˆŒ๊นŒ?

  • Target
  • Build Configuration

๋ฌผ๋ก  Target์„ ํ†ตํ•ด์„œ ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ product๊ฐ€ ์ƒ์„ฑ๋˜๋„๋ก ์„ค์ •ํ•ด ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆŒ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฌด๋ฃŒ/์œ ๋ฃŒ ๋ฒ„์ „ ๊ตฌ๋ถ„, ์œ„์ ฏ๋“ฑ ๊ฐ™์€ ์•ฑ์ด์ง€๋งŒ ๋‹ค๋ฅธ ์‚ฌ์šฉ์„ฑ์„ ์ œ๊ณตํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

(๊ด€๋ จ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์•Œ๊ณ ๊ณ„์‹œ๋ฉด ์—ฐ๋ฝ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค!!)

๋”ฐ๋ผ์„œ ํ•˜๋‚˜์˜ Target์˜ Produect๋ฅผ Build Configuration์„ ํ†ตํ•ด ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.


Build Configuration

Build Configuaration๋Š” ๋นŒ๋“œํ•  ๋•Œ ํ™˜๊ฒฝ์„ ์ œ์–ดํ•˜๋Š” ๊ฐ’ ์ •๋„๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

Untitled Untitled 1

ํ”„๋กœ์ ํŠธ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ Debug, Release๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ๊ณ , ์Šคํ‚ด์—์„œ ๋นŒ๋“œ์™€ ๋ฐฐํฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ configuartion์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ configuration์„ ์ด์šฉํ•ด์„œ ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆ ๋ณด์ž.

  • dev, stage, prod๋ฅผ ์œ„ํ•œ debug/release ๋ฅผ ๋งŒ๋“ ๋‹ค. (์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉ)
  • dev, stage, prod์— ํ•ด๋‹นํ•˜๋Š” configuration์„ ์‚ฌ์šฉํ•œ scheme์„ ๋งŒ๋“ ๋‹ค.
  • dev, stage, prod ๊ฐ๊ฐ xconfig ํŒŒ์ผ์„ ํ†ตํ•ด ํ™˜๊ฒฝ๋ณ„ ๊ฐ’์„ ์„ธํŒ…ํ•œ๋‹ค.

ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๊ณผ์ •์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๊ณ  ํ˜น์‹œ๋‚˜ ๋น ์ง„๋ถ€๋ถ„ ์žˆ๋‹ค๋ฉด ๊น€์ข…๊ถŒ๋‹˜์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

Untitled 2

๊ธฐ์กด์˜ Debug, Release๋ฅผ ๋ณต์‚ฌํ•ด์„œ dev, stage, prod ๋ฅผ ๋งŒ๋“ ๋‹ค. (dev release๋Š” ์ƒํ™ฉ์— ๋งž๊ฒŒ ๋งŒ๋“ ๋‹ค.)

![Untitled
Untitled 3
]

๊ทธ๋ฆฌ๊ณ  dev, stage, prod์— ํ•ด๋‹นํ•˜๋Š” ์Šคํ‚ด์„ ์ƒ์„ฑํ•œ๋‹ค. ์Šคํ‚ด์„ ์ƒ์„ฑํ•˜๋Š” ์ด์œ ๋Š” ํ™˜๊ฒฝ๋ณ„๋กœ edit ์Šคํ‚ด์„ ํ†ตํ•ด์„œ build configuration์„ ์ˆ˜์ •ํ•˜๋Š” ๊ณผ์ •์ด ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์‹ค์ˆ˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ๋ฏธ๋ฆฌ ๊ฐ ํ™˜๊ฒฝ์— ๋งž๋Š” ์Šคํ‚ด์„ ์ƒ์„ฑํ•œ๋‹ค.

(์ฒ˜์Œ์—๋Š” ์Šคํ‚ด์„ ํ†ตํ•ด์„œ ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์—ˆ๋Š”๋ฐ ์Šคํ‚ด์€ ๋นŒ๋“œํ•  ๋•Œ ์–ด๋–ค build configuration ์ด์šฉํ• ์ง€ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด์ง€ ์Šคํ‚ด์„ ํ†ตํ•ด ๊ฐœ๋ฐœํ™˜๊ฒฝ์„ ๋‚˜๋ˆˆ๋‹ค๋Š” ํ‘œํ˜„์€ ๋ฐ˜์ชฝ ์ž๋ฆฌ ์ •๋‹ต์ธ๊ฒƒ ๊ฐ™๋‹ค.)

Untitled 4 Untitled 5

์ด์ œ ๊ฐ ํ™˜๊ฒฝ๋ณ„๋กœ xconfig ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ํ™˜๊ฒฝ์— ๋งž๊ฒŒ build configuration์—์„œ xconfig ํŒŒ์ผ์„ ์„ค์ •ํ•ด์ค€๋‹ค.


ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์—…์„ ๋งˆ์น˜๋ฉด ์ด์ œ ๋ชจ๋“  ์„ธํŒ…์ด ๋๋‚ฌ๊ณ  xconfig ํŒŒ์ผ์„ ํ†ตํ•ด์„œ ํ™˜๊ฒฝ๋ณ„๋กœ ๊ฐ’์„ ์„ธํŒ…ํ•˜๋Š” ๊ณผ์ •๋งŒ ๋‚จ์•˜๋‹ค.

  • ํ™˜๊ฒฝ๋ณ„๋กœ ์ƒ์„ฑ๋˜๋Š” ์•ฑ์„ ๋‹ค๋ฅด๊ฒŒ โ†’ ํ™˜๊ฒฝ๋ณ„ ๋ฐฐํฌ ๊ฐ€๋Šฅ
  • ํ™˜๊ฒฝ๋ณ„๋กœ ์„ธํŒ…๋˜๋Š” API ์ฃผ์†Œ๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ โ†’ ํ™˜๊ฒฝ๋ณ„ ์„œ๋ฒ„ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๋จผ์ € ํ™˜๊ฒฝ๋ณ„๋กœ ์ƒ์„ฑ๋˜๋Š” ์•ฑ์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•ด๋ณด์ž.

// Prod.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.app
PRODUCT_NAME = EnvSetting
DEPLOY_PHASE = prod

// Stage.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.stage.app
PRODUCT_NAME = EnvSetting-stage
DEPLOY_PHASE = stage

// Dev.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.dev.app
PRODUCT_NAME = EnvSetting-dev
DEPLOY_PHASE = dev

ํ™˜๊ฒฝ๋ณ„ .xconfig ํŒŒ์ผ์—์„œ ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ ์•ฑ์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ์œ ํ•œ identifier๊ฐ’๋“ค์„ ์„ค์ •ํ•ด์ค€๋‹ค.

Untitled 6

์•ž์„œ์„œ ์šฐ๋ฆฌ๊ฐ€ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ build configuration์„ xconfig ํŒŒ์ผ์˜ ๊ฐ’์„ ๋”ฐ๋ฅด๋„๋ก ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ๊นŒ์ง€๋งŒ ์ž‘์—…์„ ํ•ด๋„ ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ ์„ธํŒ…์—์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ ๋ฏธ๋ฆฌ ์ •์˜ํ•œ ์Šคํ‚ด๋ณ„๋กœ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด ๊ฒฐ๊ณผ๋Š”? โ†’ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค.

์ด์œ ๋Š” ๋‹จ์ˆœํ•˜๋‹ค. ํƒ€๊ฒŸ์˜ ์„ค์ • ๊ฐ’๋“ค์€ ๋ฐ”๋€Œ์ง€ ์•Š์€์ฑ„๋กœ ์—ฌ์ „ํžˆ ๋‚จ์•„์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํƒ€๊ฒŸ์˜ ๋นŒ๋“œ ์„ค์ •๊ฐ’๋“ค์€ ํ”„๋กœ์ ํŠธ์˜ ๊ฐ’๋“ค์„ ์ƒ์† ๋ฐ›๊ณ  ํƒ€๊ฒŸ์˜ product์˜ ๋นŒ๋“œ ์„ค์ •๊ฐ’์€ ํƒ€๊ฒŸ์˜ ์„ค์ •๊ฐ’์„ ๋”ฐ๋ฅธ๋‹ค.

Untitled 7

๋”ฐ๋ผ์„œ ํƒ€๊ฒŸ์˜ ์„ค์ •์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค. ์ด์ œ ๋‹ค์‹œ ์Šคํ‚ด๋ณ„๋กœ ํ…Œ์ŠคํŠธํ•˜๋ฉด ํ™˜๊ฒฝ๋ณ„๋กœ ์„œ๋กœ ๋‹ค๋ฅธ ์•ฑ 3๊ฐœ๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ๋ฐฐํฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ฐ€์ •ํ•ด๋ณด์ž.

Bundle Identifier๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— TestFlight์—์„œ Stage, Prod๋ฅผ ํ˜ผ๋™ํ•ด ์‹ค์ˆ˜ํ•  ์ผ์€ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—†์–ด์ง„๋‹ค. ํ•˜์ง€๋งŒ QA์ž‘์—…์„ ํ•˜๋‹ค๋ณด๋ฉด Stage, Prod์˜ ๋ฒ„์ „์ด๋‚˜ ๋นŒ๋“œ๋„˜๋ฒ„๊ฐ€ ์ƒ์ดํ•ด์ง€๋Š”๋ฐ ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผ ํ• ๊นŒ?

๋ฌผ๋ก , ๋ธŒ๋žœ์น˜ ์ „๋žต์„ ํ†ตํ•ด์„œ ๊ด€๋ฆฌํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ xcode์—์„œ ๋นŒ๋“œ๋„˜๋ฒ„, ๋ฒ„์ „์€ .pbx ํŒŒ์ผ์„ ํ†ตํ•ด์„œ ๊ด€๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ˆ˜ํ•˜๊ธฐ ์‰ฝ๋‹ค.

Untitled 8

์˜์™ธ๋กœ ๊ฐ„๋‹จํ•œ๋ฐ ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ configuration ๋ณ„๋กœ ๋ฒ„์ „, ๋นŒ๋“œ๋„˜๋ฒ„๋ฅผ ๋‹ค ๋”ฐ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ™˜๊ฒฝ๋ณ„๋กœ API๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•ด๋ณด์ž

info.plist์— ํ™˜๊ฒฝ๋ณ„๋กœ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์„ xconfig์—์„œ ์„ค์ •ํ•˜๊ณ  ์•ฑ์ด ์‹œ์ž‘ํ•˜๋Š” ์‹œ์ ์—์„œ info.plist ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ๋œ๋‹ค.

enum DeployPhase: String {
  case prod
  case stage
  case dev
}

final class Configuration {
  private init() { }

  private static let configKey = "DeployPhase"

  // MARK: - Get Current DeployPhase
  static func getDeployPhase() -> DeployPhase {
    guard
      let configValue = Bundle.main.object(forInfoDictionaryKey: configKey) as? String,
      let phase = DeployPhase(rawValue: configValue)
    else {
      return DeployPhase.dev
    }
    return phase
  }
}
Untitled 9
import SwiftUI

@main
struct EnvSettingApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .onAppear {
          print(Configuration.getDeployPhase())
        }
    }
  }
}

๊ฒช์—ˆ๋˜ ๋ฌธ์ œ๋“ค

  • ํ™˜๊ฒฝ๋ณ„ custom flag ์‚ฌ์šฉ
  • ํ™˜๊ฒฝ๋ณ„ run script ๋ถ„๊ธฐ์ฒ˜๋ฆฌ
  • ํ™˜๊ฒฝ๋ณ„ firebase ์„ค์ •

๋“ฑ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ๋“ค์„ ๊ฒช๊ณ  ๋‚˜๋ฆ„๋Œ€๋กœ ํ•ด๊ฒฐํ•œ ๋ฐฉ๋ฒ•์€ ์ถ”ํ›„์— ํ•˜๋‚˜์”ฉ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.


์ฐธ๊ณ 

Xcode Target

iOS ํ”„๋กœ์ ํŠธ ๋ฐฐํฌ ํ™˜๊ฒฝ๋ณ„ build ์„ธํŒ…ํ•˜๊ธฐ

AES

AES

AES(Advanced Encryption Standard)๋Š” ํ˜„์žฌ ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

ECDSA, RSA ๊ฐ™์€ ๋น„๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์šฐ๋ฆฌ๋Š” AES๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ์ง€๊ฐ€ ์ค‘์š”ํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค.

  • ์•”ํ˜ธํ™”, ๋ณตํ˜ธํ™”์— ๋™์ผํ•œ ํ‚ค๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.
  • ์„œ๋ฒ„์— ํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค

๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฏ€๋กœ ์œ„์˜ ๋‘๊ฐ€์ง€ ์ •๋„๋งŒ ๋จธ๋ฆฌ์†์—์„œ ๋– ์˜ค๋ฅด๋ฉด ๋œ๋‹ค.

  • AES Key ์ƒ์„ฑ
  • AES๋ฅผ ์ด์šฉํ•œ Encrypt, Decrypt

์ˆœ์„œ๋Œ€๋กœ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์ž.

์ •๋ฆฌํ•˜๊ธฐ์— ์•ž์„œ์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด CryptoKit์„ ์ด์šฉํ•ด์„œ AES๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ณผ์ •์„ ์ •๋ฆฌํ• ๊ฑด๋ฐ ๊ฐœ์ธ์ ์œผ๋กœ ์ถ”์ฒœํ•˜์ง€ ์•Š๋Š”๋‹ค. CryptoKit์„ ์ด์šฉํ•ด ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด AES.GCM.SealedBox ํƒ€์ž…์ด ํ•„์—ฐ์ ์œผ๋กœ ํ•„์š”ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์„œ๋ฒ„์™€ ์ŠคํŽ™์„ ๋งž์ถ”๊ฑฐ๋‚˜ ์„œ๋ฒ„์™€ ํ•จ๊ป˜ ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ๋„ˆ๋ฌด ์–ด๋ ค์›Œ์ง„๋‹ค.

๋”ฐ๋ผ์„œ ๊ฐœ๋…์ •๋„๋งŒ ์ตํžˆ๊ณ  ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ CommonCrypto๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ CryptoSwift ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ ๊ทน ์ถ”์ฒœํ•œ๋‹ค.

AES encryption in Swift
https://github.com/krzyzanowskim/CryptoSwift


1) AES ํ‚ค ์ƒ์„ฑ

AES๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด์ „์— ๋ดค๋˜ ๋น„๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๋‹ฌ๋ฆฌ ๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ ๋น„๋ฐ€ํ‚ค๋งŒ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  IV(Initial Vector)์— ๋”ฐ๋ผ ๊ฐ™์€ ํ‚ค๋กœ ๊ฐ™์€ ํ‰๋ฌธ์„ ์•”ํ˜ธํ™” ํ•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค.

๊ฒฐ๊ตญ ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™” ๊ณผ์ •์„ ์œ„ํ•ด์„œ๋Š” ๋Œ€์นญํ‚ค, IV๊ฐ€ ํ•„์š”ํ•˜๋‹ค

final class AES256 {
  private let dataStorage: KeyChainDataStorage
  private var key: SymmetricKey?
  private var iv: AES.GCM.Nonce?

  init(
    dataStorage: KeyChainDataStorage
  ) {
    self.dataStorage = dataStorage
    generateKey()
  }

  /// Make AES256 RandomKey, 16 Byte inital vector
  private func generateKey() {
    let refStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    var randomStr = ""
    for _ in 0..<16 {
      randomStr += String(refStr.randomElement()!)
    }
    let randomIV: [UInt8] = Array(randomStr.utf8)

    do {
      self.key = SymmetricKey(size: .bits256)
      self.iv = try AES.GCM.Nonce(data: randomIV)
    } catch let err {
      print("Make IV Error:", err.localizedDescription)
    }
  }
}

AES256์„ ์‚ฌ์šฉํ•˜๋ฉด 32Byte์˜ ๋žœ๋คํ•œ ํ‚ค, 16Byte์˜ ๋žœ๋คํ•œ IV๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ String ํƒ€์ž… ํ•˜๋‚˜๋‹น 1Byte์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 32, 16์˜ ๊ธธ์ด๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.

์œ„์˜ ์ฝ”๋“œ์—์„œ ๊ตณ์ด String์˜ ๋ฒ”์œ„๋ฅผ 09, azA~Z๋กœ ๋‘” ์ด์œ ๋Š” utf8 ๋ณ€ํ™˜์‹œ ํ•ด๋‹น ๋ฒ”์œ„๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ๊ฐ€๋ณ€์ ์œผ๋กœ ํ•œ ๊ธ€์ž๋‹น 2Byte์˜ ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„์ ์œผ๋กœ ๊ธธ์ด๋ฅผ ์ œํ•œํ–ˆ๋‹ค.


2) Encrypt, Decrypt

/// AES - Encrypt plain string to rsa base64 String
  func encryptByAES(
    plainString: String
  ) -> AES.GCM.SealedBox? {
    guard
      let key = key,
      let iv = iv,
      let data = plainString.data(using: .utf8),
      let sealedBox = try? AES.GCM.seal(data, using: key, nonce: iv)
    else { return nil }

    return sealedBox
  }

Encryption์˜ ๊ฒฝ์šฐ ์•ž์„œ ์ƒ์„ฑํ•œ ๋Œ€์นญํ‚ค์™€ iv๋ฅผ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์•”ํ˜ธํ™” ๊ฒฐ๊ณผ๋กœ ๋‚˜์˜ค๋Š” Type์ด AES.GCM.SealedBox๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

/// AES - Decrypt rsa base64 String to plain String
  func decryptByAES(
    encryptedBox: AES.GCM.SealedBox
  ) -> String? {
    guard
      let key = key,
      let sealedBox = try? AES.GCM.SealedBox(
        nonce: encryptedBox.nonce,
        ciphertext: encryptedBox.ciphertext,
        tag: encryptedBox.tag
      ),
      let decryptedData = try? AES.GCM.open(sealedBox, using: key)
    else { return nil }

    return String(data: decryptedData, encoding: .utf8)
  }

๋ณตํ˜ธํ™” ๊ณผ์ •์—์„œ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด AES.GCM.SealedBox์ธ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  AES.GCM.SealedBox ๋ฅผ ์ƒ์„ฑํ• ๋•Œ, tag๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”๋ฐ ์ด๋Š” Encryption์„ ํ†ตํ•ด ์ƒ์„ฑ๋œ AES.GCM.SealedBox ์˜ tag์™€ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ์  ๋•Œ๋ฌธ์— Encryption์˜ ๊ฒฐ๊ณผ๊ฐ’์„ String์ด ์•„๋‹Œ AES.GCM.SealedBox ๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์—์„œ๋งŒ AES ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์ง€๋งŒ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„์™€AES.GCM.SealedBox ํƒ€์ž…์„ ์ฃผ๊ณ ๋ฐ›์ง€ ์•Š๊ณ ์„œ๋Š” ์„œ๋กœ ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

๋ฌผ๋ก  ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” Base64String, HexString ํƒ€์ž…์œผ๋กœ ์•”ํ˜ธํ™” ๊ฒฐ๊ณผ๊ฐ’์„ ์ฃผ๊ณ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.


3) ํ‚ค ์ „์†ก

๋Œ€์นญํ‚ค์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„์— ํ‚ค๋ฅผ ์–ด๋–ป๊ฒŒ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๋‚ผ๊ฒƒ์ธ๊ฐ€? ๋„ ๊ต‰์žฅํžˆ ์ค‘์š”ํ•œ ๋ฌธ์ œ์ด๋‹ค.

๋ฌผ๋ก  ํด๋ผ์ด์–ธํŠธ ๊ฐœ๋ฐœ์ž ํ˜ผ์ž์„œ ๊ณ ๋ฏผํ•  ๋ฌธ์ œ๋Š” ์•„๋‹ˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๋Œ€์นญํ‚ค๋ฅผ ๋น„๋Œ€์นญํ‚ค๋ฅผ ํ†ตํ•ด ์•”ํ˜ธํ™” ํ•˜๊ณ  ๋น„๋Œ€์นญํ‚ค ๊ณต๊ฐœํ‚ค๋ฅผ ํ•จ๊ป˜ ๋ณด๋‚ด์„œ ์„œ๋ฒ„์—์„œ ๋ณตํ˜ธํ™”ํ•ด์„œ ํ‚ค๋ฅผ ์–ป์–ด๋‚ด๋Š” ๋ฐฉ์‹์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๊ฒƒ ๊ฐ™๋‹ค.

(์‚ฌ์‹ค ๊ทธ๊ฒƒ๋ฐ–์— ์•ˆํ•ด๋ด„)

Xcode ๊ฐœ๋ฐœ(๋ฐฐํฌ)ํ™˜๊ฒฝ ๋‚˜๋ˆ„๊ธฐ - 2

๊ฐœ๋ฐœํ™˜๊ฒฝ ๋‚˜๋ˆ„๊ธฐ - 2

Custom Flag ์„ค์ •

์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ํ™˜๊ฒฝ๋ณ„๋กœ ๋ถ„๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

  • deploy phase (plist ์‚ฌ์šฉ)
  • ์ „์ฒ˜๋ฆฌ๋ฌธ ์‚ฌ์šฉ

๋ฐฉ๋ฒ•์€ ๋งŽ์ง€๋งŒ ์œ„์˜ ๋‘ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฒซ๋ฒˆ์จฐ ๋ฐฉ๋ฒ•์€ ์ง€๋‚œ๋ฒˆ์— ์ •๋ฆฌํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‘๋ฒˆ์จฐ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด์ž.

์ „์ฒ˜๋ฆฌ๋ฌธ์€ ์ปดํŒŒ์ผ ์ด์ „์— ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฌธ์žฅ์œผ๋กœ ์ฃผ๋กœ C์–ธ์–ด์—์„œ #defin์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉํ–ˆ์—ˆ๋Š”๋ฐ iOS์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ?

  • OS๊ตฌ๋ถ„ ๋ฐ ๋ฒ„์ „ ๋ถ„๊ธฐ
  • Flag๋ฅผ ์ด์šฉํ•œ ์ „์ฒ˜๋ฆฌ
// MARK: - OS ๋ถ„๊ธฐ์ฒ˜๋ฆฌ
#if os(iOS)
print("iOS")
#elseif os(macOS)
print("macOS")
#else
print("other OS")
#endif

// MARK: - Flag ๋ถ„๊ธฐ์ฒ˜๋ฆฌ
#if DEBUG
print("Debug")
#else
print("Relase")
#endif

(์ „์ฒ˜๋ฆฌ๋ฌธ์ด ๋ญ์•ผ? ํ–ˆ๋˜ ๋ถ„๋“ค๋„ ์•„๋งˆ ์œ„์˜ ์ฝ”๋“œ๋Š” ํ•œ๋ฒˆ์”ฉ์€ ๋ดค๋˜ ๊ธฐ์–ต์ด ์žˆ์„๊ฒ๋‹ˆ๋‹ค)

Swift์—๋Š” ์ „์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์—†๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ณ ๊ณ„์…จ๋‚˜์š”?? -> ํ•ด๋‹น ๋‚ด์šฉ์€ ๋นŒ๋“œ๊ณผ์ •์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ œ๋ชฉ์„ ํ†ตํ•ด์„œ๋„ ์•Œ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” Flag๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐœ๋ฐœํ™˜๊ฒฝ๋ณ„๋กœ ์ „์ฒ˜๋ฆฌ๋ฌธ์„ ์ด์šฉํ•  ์˜ˆ์ •์ด๋‹ค.

Untitled

ํ”„๋กœ์ ํŠธ๋ฅผ ์ฒ˜์Œ ์ƒ์„ฑํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ DEBUG Flag๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ธํŒ…์—์„œ ๋ฐ”๋กœ ๊ฐ’์„ ์ˆ˜์ •ํ•ด๋„ ๋˜์ง€๋งŒ Build Configuration์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์„ .xconfig ํŒŒ์ผ์—์„œ ์ •๋ฆฌํ•˜๊ณ  ์„ค์ •ํ•˜๋Š” ๋ฒ•์„ ์ง€๋‚œ๋ฒˆ์— ์ •๋ฆฌ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•ด๋ณด์ž.

// MARK: - Prod.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.app
PRODUCT_NAME = EnvSetting
CUSTOM_FLAG = PROD
DEPLOY_PHASE = prod

// MARK: - Stage.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.stage.app
PRODUCT_NAME = EnvSetting-stage
CUSTOM_FLAG = STAGE
DEPLOY_PHASE = stage

// MARK: - Dev.xconfig
PRODUCT_BUNDLE_IDENTIFIER = com.bran.envsetting.dev.app
PRODUCT_NAME = EnvSetting-dev
CUSTOM_FLAG = DEV
DEPLOY_PHASE = dev
Untitled 1

๋ฐฉ๋ฒ• ์ž์ฒด๋Š” ์ง€๋‚œ๋ฒˆ bundle identifier, app name ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์™„์ „ํžˆ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žต

struct ContentView: View {
  var body: some View {
    VStack {
      Image(systemName: "globe")
        .imageScale(.large)
        .foregroundColor(.accentColor)

      #if DEV
      Text("Hello, DEV world!")
      #elseif STAGE
      Text("Hello, STAGE world!")
      #else
      Text("Hello, world!")
      #endif
    }
    .padding()
  }
}

Run Script ๋ถ„๊ธฐ์ฒ˜๋ฆฌ

firebase, swiftgen๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ๋‹ค๊ตญ์–ด ํŒŒ์ผ ๊ฐ™์€ ๊ฒฝ์šฐ Build Phase์—์„œ run script๋ฅผ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ๋กœ ๋นŒ๋“œํ•˜๋Š” ๊ณผ์ • ์ค‘์— ์†Œ์Šค ํŒŒ์ผ๋“ค์„ ์ƒ์„ฑํ•œ๋‹ค.

case "${CONFIGURATION}" in
  "Debug(Dev)" | "Release(Dev)" )
    echo "DEV" ;;
  "Debug(Stage)" | "Release(Stage)" )
    echo "STAGE" ;;
  "Debug" | "Release" )
    echo "PROD" ;;
*)
;;
esac

์œ„์™€ ๊ฐ™์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  build log์—์„œ ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ’์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํด๋กœ์ € - 02

ํด๋กœ์ €๋ฅผ ์ด์šฉํ•œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™”

let testLabel: UILabel = {
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
  }()

UIKit์—์„œ ๋ทฐ๋ฅผ ์ฝ”๋“œ๋กœ ์งœ๋ณด์‹  ๋ถ„๋“ค์€ ์•„๋งˆ ์œ„์™€ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋ทฐ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋งŒ๋“  ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ๋ณด์…จ์„๊ฒ๋‹ˆ๋‹ค. (์ €๋Š” ์‚ฌ์‹ค ์Šค์œ ๋งŒ ํ•ด์„œ ์ž˜ ๋ชจ๋ฆ…๋‹ˆ๋‹ค ํ—คํ—ฟ)

  • ์™œ ์ €๋ ‡๊ฒŒ UILabel ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋Š”์ง€
  • ์œ„์˜ ๋ฐฉ์‹๊ณผ ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ์˜ ์ฐจ์ด์ ์ด ๋ฌด์—‡์ธ์ง€

์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.


1) ํด๋กœ์ €๋ฅผ ์ด์šฉํ•œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™”

์œ„์˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ป๊ฒŒ UILabel ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š”์ง€ ๋ฐ”๋กœ ์ดํ•ดํ•˜์…จ๋‚˜์š”? ์งˆ๋ฌธ์„ ๋ฐ”๊ฟ”์„œ ()๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜์…จ๋‚˜์š”?

์•„๋งˆ ํด๋กœ์ €์— ๋Œ€ํ•ด ์ œ๋Œ€๋กœ ํ•™์Šต ํ•˜์…จ๋˜ ๋ถ„๋“ค์€ ์™œ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜์‹œ๋Š”๋ฐ ํฐ ์–ด๋ ค์›€์ด ์—†์—ˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜๋‚˜์”ฉ ๋œฏ์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// 1)	
	{
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
  }

์šฐ์„  ์œ„์˜ ์ € { } ๋กœ ๊ฐ์‹ธ์ง„ 1๋ฒˆ ์ฝ”๋“œ๋ญ‰์น˜(?)์˜ ํƒ€์ž…์ด ๋ฌด์—‡ ์ผ๊นŒ์š”?

// 2)
let b = { () -> UILabel in
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
}

์•„๋งˆ 2๋ฒˆ ์ฝ”๋“œ๋ฅผ ๋ณด๋Š” ์ˆœ๊ฐ„ 1๋ฒˆ ์ฝ”๋“œ ๋ญ‰์น˜์˜ ํƒ€์ž…์ด () โ†’ UILabel ํƒ€์ž…์˜ ํด๋กœ์ €์ž„์„ ๋ˆˆ์น˜ ์ฑ„์…จ์„๊ฒ๋‹ˆ๋‹ค.

ํ‹€๋ฆฌ์…จ๋‹ค๊ณ  ํ•ด๋„ ์ „ํ˜€ ๊ฑฑ์ •ํ•˜์‹ค ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค 1๋ฒˆ ์ฝ”๋“œ๋Š” Swift๋„ ํƒ€์ž…์ถ”๋ก ์„ ๋ชปํ•˜๋Š” ์ฝ”๋“œ๋‹ˆ๊นŒ์š” ใ…Žใ…Ž

์™œ 1๋ฒˆ ์ฝ”๋“œ๋ฅผ Swift๊ฐ€ ํƒ€์ž…์ถ”๋ก ์— ์‹คํŒจํ•˜๋Š”์ง€๋Š” ๋งˆ์ง€๋ง‰์— ๋”ฐ๋กœ ์ •๋ฆฌํ•˜๊ธฐ๋กœ ํ•˜๊ณ  ํ•˜๋˜ ์ •๋ฆฌ๋ฅผ ์ด์–ด๊ฐ€๋ด…์‹œ๋‹ค.

let testLabel: UILabel = {
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
  }()

์ด์ œ ()๊ฐ€ ๋ถ™์–ด์•ผ๋งŒ ํ•˜๋Š” ์ด์œ ๋ฅผ ์•„์‹œ๊ฒ ๋‚˜์š”? () โ†’ UILabel ํƒ€์ž…์˜ ํด๋กœ์ €๋ฅผ ์‹คํ–‰์‹œํ‚จ ๊ฒฐ๊ณผ๊ฐ’์„ testLabel์— ๋„ฃ์–ด์ฃผ๊ณ  ์žˆ๋Š” ๊ฑฐ์ฃ !!

๊ทธ๋Ÿผ ํด๋กœ์ €๋ฅผ ํ†ตํ•ด์„œ ์—ฐ์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฅผ ์ด์šฉํ•ด์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ดˆ๊ธฐํ™” ์‹œํ‚ค๊ณ  ์žˆ๋Š”๋ฐ ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ์™€์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ผ๊นŒ์š”?


2) ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ์™€์˜ ์ฐจ์ด

์ฐจ์ด์ ์€ ์—ฐ์‚ฐ์˜ ํšŸ์ˆ˜์— ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋Š” ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์—ฐ์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ˜๋ฉด ํด๋กœ์ €๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™”๋œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋Š” ์ตœ์ดˆ ์ดˆ๊ธฐํ™” ์‹œ์ ์— ํ•œ๋ฒˆ ์—ฐ์‚ฐ๋˜๊ณ  ์ดํ›„์—๋Š” ์ €์žฅ๋œ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.


let a = { 
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
}

Swift๋Š” a ์˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. (์ปดํŒŒ์ผ ํ•˜์‹œ๋ฉด ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค)

ํด๋กœ์ €์˜ ์ธ์ž๊ฐ€ ์—†๊ณ  ๋ฐ˜ํ™˜ํƒ€์ž…์„ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ ์™œ () โ†’ UILabel์ด๋ผ๋Š” ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ• ๊นŒ์š”?

UILabel์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํด๋กœ์ € ๋‚ด๋ถ€์—์„œ returnํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํด๋กœ์ € ๋‚ด๋ถ€์˜ ๋…๋ฆฝ์ ์ธ ์ง€์—ญ๋ณ€์ˆ˜์˜ label์„ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํด๋กœ์ € ์™ธ๋ถ€์˜ ์ž…์žฅ์—์„œ๋Š” ํƒ€์ž… ์ถ”๋ก ์„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!!

๋™์ผํ•œ ์ด์œ ๋กœ

let testLabel: UILabel = {
    let label = UILabel()
    label.text = "Lunch Screen"
    label.font = .systemFont(ofSize: 30, weight: .bold)
    label.textColor = .black
    return label
  }()

์—์„œ๋„ UILabel์ด๋ผ๋Š” ํƒ€์ž…์„ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค!!


์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ

[[์Šค์œ„ํ”„ํŠธ(Swift) ํ”„๋กœ๊ทธ๋ž˜๋ฐ] - Closure๋ฅผ ์ด์šฉํ•ด ์ €์žฅ ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ๋“ค์—ˆ๋˜ ์˜๋ฌธ์ ๋“ค](https://jayb-log.tistory.com/259)

[Why can't the Swift compiler infer this closure's type?](https://stackoverflow.com/questions/42534207/why-cant-the-swift-compiler-infer-this-closures-type)

[iOS] WebSocket - CLOSE_WAIT

CLOSE_WAIT

WebSocket์„ ์—ฐ๊ฒฐํ•ด์„œ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋˜ ์ค‘ ๋ฐœ์ƒํ–ˆ๋˜ ๋ฒ„๊ทธ(?)๋ฅผ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

  • StarScream, URLSessionSocket์„ ํ†ตํ•ด ๊ตฌํ˜„ํ•˜๋Š” ๊ณผ์ •๋ณด๋‹ค๋Š” ํ˜„์ƒ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.
  • Socket ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ๋Š” ์—…๋น„ํŠธ๋ฅผ ์ด์šฉ

์šฐ์„  ์—…๋น„ํŠธ ์†Œ์ผ“์„ ํ„ฐ๋ฏธ๋„์—์„œ ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž

Untitled

< {
"type":"ticker",
"code":"KRW-BTC",
"opening_price":29398000,
"high_price":29528000,
"low_price":29350000,
"trade_price":29468000,
"prev_closing_price":29420000.00000000,
"acc_trade_price":39734960333.20671000,
"change":"RISE",
"change_price":48000.00000000,
"signed_change_price":48000.00000000,
"change_rate":0.0016315432,
"signed_change_rate":0.0016315432,
"ask_bid":"BID",
"trade_volume":0.01749575,
"acc_trade_volume":1349.62787321,
"trade_date":"20230205",
"trade_time":"103530",
"trade_timestamp":1675593330855,
"acc_ask_volume":647.32427056,
"acc_bid_volume":702.30360265,
"highest_52_week_price":57678000.00000000,
"highest_52_week_date":"2022-03-28",
"lowest_52_week_price":20700000.00000000,
"lowest_52_week_date":"2022-12-30",
"market_state":"ACTIVE",
"is_trading_suspended":false,
"delisting_date":null,
"market_warning":"NONE",
"timestamp":1675593330915,
"acc_trade_price_24h":81916979573.45246000,
"acc_trade_volume_24h":2780.05924818,
"stream_type":"SNAPSHOT"
}>

์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ๋˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๊ฐ’๋“ค์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ™ˆํŽ˜์ด์ง€์—์„œ ์„ค๋ช…ํ•œ idle timeOut๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์†Œ์ผ“ ์—ฐ๊ฒฐ ํ›„, 120์ดˆ ๊ฐ„ ๋ฐ์ดํ„ฐ ์†ก ์ˆ˜์‹ ์ด ์—†๋Š” ์ƒํƒœ๋กœ ๋Œ€๊ธฐ ํ•ด๋ณด์•˜๋‹ค. (ping, pong x)

Untitled 1

์•ฝ 120์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด DisConnected ๋˜๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


์ด์ œ ์œ„์˜ ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ Starscream์„ ์ด์šฉํ•ด ๊ตฌํ˜„ํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž

final class SocketManager {
  static let shared = SocketManager()
  private var socket: WebSocket?

  private init() {
    setupWebSocket()
  }

  deinit {
    socket?.delegate = nil
  }

  private func setupWebSocket() {
    let url = URL(string: "wss://api.upbit.com/websocket/v1")!
    var request = URLRequest(url: url)
    request.timeoutInterval = 5
    socket = WebSocket(request: request)
  }

  func connect() {
    socket?.delegate = self
    socket?.connect()
  }

  func disconnect() {
    socket?.disconnect()
  }

  private func sendMessage(_ message: String) {
    socket?.write(string: message)
  }

  private func sendRequest() -> String {
    """
    [{"ticket":"\(UUID())"},{"type":"orderbook","codes":["KRW-BTC"]}]
    """
  }
}

extension SocketManager: WebSocketDelegate {
  func didReceive(event: WebSocketEvent, client: WebSocket) {
    switch event {
    case .connected(let headers):
      print("websocket is connected: \(headers)")
    case .disconnected(let reason, let code):
      print("websocket is disconnected: \(reason) with code: \(code)")
    case .text(let text):
      print("received text: \(text)")
    case .binary(let data):
      print("Received data: \(data.count)")
    case .ping(_):
      print("Ping: ")
    case .pong(_):
      print("Pong: ")
    case .viabilityChanged(_):
      print("viabilityChanged")
    case .reconnectSuggested(_):
      print("reconnectSuggested")
    case .cancelled:
      print("websocket is canclled")
    case .error(let error):
      print("websocket is error = \(error!)")
    }
  }
}

ํ„ฐ๋ฏธ๋„์—์„œ ๋ณธ ๊ฒฐ๊ณผ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ํ•˜๊ณ , ํ‹ฐ์ผ“์„ ๋ฉ”์‹œ์ง€๋กœ ๋ณด๋‚ด๋ฉด ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

image

ํ•˜์ง€๋งŒ idle timeout๋ฅผ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด, ํด๋ผ์ด์–ธํŠธ ๋‹จ์—์„œ CloseWait ์ƒํƒœ๋กœ ๋ฌดํ•œํžˆ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ๋ฌธ์ œ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

Untitled 2

TCP ์ข…๋ฃŒ์‹œ์ ์˜ 4way-handshake ๊ณผ์ •์—์„œ ์‚ดํŽด๋ณด๋ฉด,

์„œ๋ฒ„๊ฐ€ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„๊ฐ€ Active close(์™ผ์ชฝ), ํด๋ผ์ด์–ธํŠธ๊ฐ€ Passive close(์˜ค๋ฅธ์ชฝ)์ด๋‹ค.

ํ˜„์žฌ ์„œ๋ฒ„์—์„œ ์ข…๋ฃŒํ•˜๊ฒ ๋‹ค๋Š” Fin์„ ๋ณด๋‚ด๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•ด๋‹น ์‹ ํ˜ธ๋ฅผ ๋ฐ›๊ณ  CloseWait ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋œ ์ƒํƒœ๋กœ ๋จธ๋ฌผ๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด๋‹ค. ๊ทธ๋Ÿผ ์„œ๋ฒ„๋„ ํด๋ผ์ด์–ธํŠธ๋„ ์ข…๋ฃŒํ•  ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ๊ณ„์† ์ข…๋ฃŒํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฑธ๊นŒ?

๋‹คํ–‰ํžˆ ๊ทธ๊ฑด ์•„๋‹ˆ๋‹ค. Active Close ์—์„œ๋Š” Fin ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๊ณ  ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•œ๋‹ค. ๋ฌธ์ œ๋Š” ์„œ๋ฒ„์—์„œ ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ๋Š์—ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๋‹จ์˜ CloseWait์€ ๋‚จ๋Š”๊ฒƒ์ด๋‹ค.

(๋ฌผ๋ก  ๋ฐ˜๋Œ€์˜ ์ƒํ™ฉ๋„ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค)


์ง€๊ธˆ ๋‹น์žฅ TCP ํ•ธ๋“œ์‰์ดํฌ๋ฅผ ๊ตฌํ˜„ํ•  ์ž์‹ ๋„ ์—†๊ฑฐ๋‹ˆ์™€โ€ฆ ์‹œ๊ฐ„๋„ ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธ‰ํ•œ๋Œ€๋กœ URLSession์„ ์ด์šฉํ–ˆ์„ ๋•Œ์˜ ๊ฒฐ๊ณผ๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

image_(1)

โ“โ“โ“โ“

์ •์ƒ์ ์œผ๋กœ ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์‹ฌ์ง€์–ด Starscream 3.1.1 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์—๋„ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

3.x โ†’ 4.x Starscream ์œผ๋กœ ๊ฐ€๋ฉด์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งŽ์ด ๋ฐ”๋€Œ์–ด์„œ ์ •ํ™•ํ•œ ์›์ธ์„ ํŒŒ์•…ํ•˜์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๋กœ ์˜ˆ์ƒํ•œ๋‹ค.

public convenience init(request: URLRequest, certPinner: CertificatePinning? = FoundationSecurity(), compressionHandler: CompressionHandler? = nil, useCustomEngine: Bool = true) {
        if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *), !useCustomEngine {
            self.init(request: request, engine: NativeEngine())
        } else if #available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *) {
            self.init(request: request, engine: WSEngine(transport: TCPTransport(), certPinner: certPinner, compressionHandler: compressionHandler))
        } else {
            self.init(request: request, engine: WSEngine(transport: FoundationTransport(), certPinner: certPinner, compressionHandler: compressionHandler))
        }
    }

ํ˜„์žฌ 4.x starscream์˜ ๊ฒฝ์šฐ, socket์„ initํ•˜๋Š” ์‹œ์ ์— userCustomEngine์„ ๋””ํดํŠธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •๋˜์–ด์„œ TCPTransport๋ฅผ ์‚ฌ์šฉํ•˜๋Š” WSEngine์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

socket = WebSocket(request: request, engine: NativeEngine()) ์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•ด๋ณธ ๊ฒฐ๊ณผ ์ •์ƒ์ ์œผ๋กœ ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public class NativeEngine: NSObject, Engine, URLSessionDataDelegate, URLSessionWebSocketDelegate {
    private var task: URLSessionWebSocketTask?
    weak var delegate: EngineDelegate?

    public func register(delegate: EngineDelegate) {
        self.delegate = delegate
    }

    public func start(request: URLRequest) {
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
        task = session.webSocketTask(with: request)
        doRead()
        task?.resume()
    }

    public func stop(closeCode: UInt16) {
        let closeCode = URLSessionWebSocketTask.CloseCode(rawValue: Int(closeCode)) ?? .normalClosure
        task?.cancel(with: closeCode, reason: nil)
    }

    public func forceStop() {
        stop(closeCode: UInt16(URLSessionWebSocketTask.CloseCode.abnormalClosure.rawValue))
    }

    public func write(string: String, completion: (() -> ())?) {
        task?.send(.string(string), completionHandler: { (error) in
            completion?()
        })
    }

    public func write(data: Data, opcode: FrameOpCode, completion: (() -> ())?) {
        switch opcode {
        case .binaryFrame:
            task?.send(.data(data), completionHandler: { (error) in
                completion?()
            })
        case .textFrame:
            let text = String(data: data, encoding: .utf8)!
            write(string: text, completion: completion)
        case .ping:
            task?.sendPing(pongReceiveHandler: { (error) in
                completion?()
            })
        default:
            break //unsupported
        }
    }

    private func doRead() {
        task?.receive { [weak self] (result) in
            switch result {
            case .success(let message):
                switch message {
                case .string(let string):
                    self?.broadcast(event: .text(string))
                case .data(let data):
                    self?.broadcast(event: .binary(data))
                @unknown default:
                    break
                }
                break
            case .failure(let error):
                self?.broadcast(event: .error(error))
            }
            self?.doRead()
        }
    }

    private func broadcast(event: WebSocketEvent) {
        delegate?.didReceive(event: event)
    }
    
    public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
        let p = `protocol` ?? ""
        broadcast(event: .connected([HTTPWSHeader.protocolName: p]))
    }
    
    public func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
        var r = ""
        if let d = reason {
            r = String(data: d, encoding: .utf8) ?? ""
        }
        broadcast(event: .disconnected(r, UInt16(closeCode.rawValue)))
    }
}

NativeEngine ๊ตฌํ˜„์ฒด๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด URLSession์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. (ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋งŒ๋“  ์ฝ”๋“œ์™€ ์‹ฑํฌ๋กœ์œจ 99%)

URLSessionSocket์„ iOS13 ๋ถ€ํ„ฐ ์ง€์›ํ•˜๋ฉด์„œ, StarScream๋„ URLSession์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ๋œ๊ฒƒ ๊ฐ™๋‹ค.

Engine์ด ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ์—ญํ• ์„ ๋‹ด๋‹นํ•ด์ฃผ๊ณ  ์žˆ๋Š”์ง€ ๊นŒ์ง€๋Š” ํŒŒ์•…ํ•˜์ง€ ๋ชปํ–ˆ์ง€๋งŒ TCP ์ข…๋ฃŒ์‹œ์ ์˜ ํ•ธ๋“œ์‰์ดํฌ ๊ณผ์ •์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ณ  ์žˆ๊ณ , Starscream 4.x ๋ฒ„์ „์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด NativeEngine์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

@ChaNoo97

[SwiftUI] NavigationLink in List Item

List Item ์•ˆ์— ๋ฒ„ํŠผ์ด ์—ฌ๋Ÿฌ๊ฐœ ์žˆ๋Š” ๊ฒฝ์šฐ

List Item ๋‚ด๋ถ€์— NavigationLink๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

List Item ๋‚ด๋ถ€์— NavigationLink๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์žˆ๋Š” ๊ฒฝ์šฐ

์ •๋ฆฌํ•˜๊ธฐ

ECDSA - 1

ECDSA

ECDSA(Elliptic Curve Digital Signature Algorithm)๋Š” ๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”์˜ ํ•œ ์œ ํ˜•์œผ๋กœ, ํƒ€์› ๊ณก์„  ์•”ํ˜ธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋””์ง€ํ„ธ ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค.

ECDSA ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋˜์–ด์„œ ์•”ํ˜ธํ™”๋ฅผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ๋Š” ์ •ํ™•ํžˆ ๋ชจ๋ฅธ๋‹ค. ๋ชฉํ‘œ๋Š” ECDSA๋ฅผ Swift๋ฅผ ํ†ตํ•ด์„œ ๊ตฌํ˜„ํ•ด์„œ ์ด์šฉํ•˜๋Š”๋ฐ ์ค‘์ ์„ ๋‘๊ณ  ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค

๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”, ๋””์ง€ํ„ธ ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜

ECDSA ์„ค๋ช…์—์„œ ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๋”๋ผ๋„ 2๊ฐœ์˜ ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ค ๋ฉ”์„œ๋“œ๋“ค์ด ํ•„์š”ํ•œ์ง€ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Private Key, Public Key Pair ์ƒ์„ฑ
  • Private Key๋ฅผ ํ†ตํ•œ Signature ์ƒ์„ฑ
  • Public Key๋ฅผ ํ†ตํ•œ Signature Validation

๋Œ€์นญํ‚ค์™€ ๋น„๋Œ€์นญํ‚ค์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๋ฉด์„œ ๋‹ค๋ค˜๋˜ ๋ถ€๋ถ„๋“ค์ž…๋‹ˆ๋‹ค

์ˆœ์ฐจ์ ์œผ๋กœ ํ•˜๋‚˜์”ฉ ๊ตฌํ˜„ํ•ด๋ณด๋ฉด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์ž


1) Key Pair ์ƒ์„ฑ

ECDSA๊ฐ€ ์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ์ง€ ๋ชจ๋ฅด๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋‚˜์š”?

์•„์ฃผ ๋‹คํ–‰ํžˆ๋„ ์• ํ”Œ์€ ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•ด CryptoKit ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ๊ณ  ์‚ฌ์šฉํ•˜๋Š” ์ŠคํŽ™์— ๋งž๊ฒŒ P256, P348, P521, Curve25519๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

Untitled

(๊ฐ ์ˆซ์ž๊ฐ€ ์˜๋ฏธํ•˜๋Š”๊ฑด Key Size๋กœ ์ด๋ฏธ ๊ตฌํ˜„๋œ๊ณณ๊ณผ ๋งž์ถฐ์ค˜์•ผ ํ•œ๋‹ค. ECDSA256์€ P256์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค)

import CryptoKit
import Foundation

final class ECDSA {
  private let privateKey: P256.Signing.PrivateKey
  private let publicKey: P256.Signing.PublicKey

  // MARK: - Generate ECDSA Key Pair
  init() {
    self.privateKey = .init()
    self.publicKey = privateKey.publicKey
  }

  func getPrivateKey() -> String {
    privateKey.derRepresentation.base64EncodedString()
  }

  func getPublicKey() -> String {
    publicKey.derRepresentation.base64EncodedString()
  }
}

์ฝ”๋“œ์—์„œ ํ™•์ธํ•ด์•ผ ๋  ๋ถ€๋ถ„์€

  • private key๋ฅผ ํ†ตํ•ด์„œ public key๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค
  • private key์˜ representation ์ข…๋ฅ˜

์ฒซ๋ฒˆ์งธ๋Š” ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‘๋ฒˆ์งธ representation์˜ ์ข…๋ฅ˜๋Š” ์„œ๋ฒ„๋‚˜ ์ด๋ฏธ ๊ตฌํ˜„๋œ ๊ณณ๊ณผ ํ˜•ํƒœ๋ฅผ ๋งž์ถฐ์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ฒ˜์Œ ๊ตฌํ˜„ํ•  ๋•Œ ์ด๋ถ€๋ถ„์—์„œ ์• ๋ฅผ ์ข€ ๋จน์—ˆ๋Š”๋ฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ข…๋ฅ˜์™€ ํŠน์„ฑ์„ ํ™•์ธํ•ด๋ณด์ž

/// Creates a P-256 private key for signing from a collection of bytes.
///
/// - Parameters:
///   - rawRepresentation: A raw representation of the key as a collection of
/// contiguous bytes.
public init<Bytes>(rawRepresentation: Bytes) throws where Bytes : ContiguousBytes

/// Creates a P-256 private key for signing from a Privacy-Enhanced Mail
/// PEM) representation.
///
/// - Parameters:
///   - pemRepresentation: A PEM representation of the key.
@available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *)
public init(pemRepresentation: String) throws

/// Creates a P-256 private key for signing from a Distinguished Encoding
/// Rules (DER) encoded representation.
///
/// - Parameters:
///   - derRepresentation: A DER-encoded representation of the key.
@available(iOS 14.0, macOS 11.0, watchOS 7.0, tvOS 14.0, *)
public init<Bytes>(derRepresentation: Bytes) throws where Bytes : RandomAccessCollection, Bytes.Element == UInt8

/// - Parameters:
///   - x963Representation: An ANSI x9.63 representation of the key.
public init<Bytes>(x963Representation: Bytes) throws where Bytes : ContiguousBytes

์šฐ์„  ์ข…๋ฅ˜๋งŒ ๋ณด๋ฉด 4๊ฐ€์ง€์˜ Representation์ด ์กด์žฌํ•˜๊ณ  pemRepresentation์„ ์ œ์™ธํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” Data Type์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

1) rawRepresentation

์˜๋ฏธ ๊ทธ๋Œ€๋กœ ๋ณ„๋‹ค๋ฅธ ๊ทœ์น™์—†์ด ๋‹จ์ˆœํžˆ Data Type์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์„œ๋ฒ„์—์„œ ๋‹ค๋ฅธ Representation์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋”๋ผ๋„ raw์—์„œ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ์—์„œ Private Key๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ €์žฅํ•  ๋•Œ๋Š” rawRepresentation ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค

2) pemRepresentation

pem์€ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ์•”ํ˜ธํ™” ํ˜•์‹์œผ๋กœ Base64๋กœ ์ธ์ฝ”๋”ฉ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ์ž‘๊ณผ ๋์— ํŠน์ •ํ•œ ํƒœ๊ทธ๋ฅผ ๋ถ™์—ฌ ํ‘œํ˜„ํ•œ๋‹ค.

pem ํ˜•์‹์œผ๋กœ public key๋ฅผ ์ƒ์„ฑํ•˜๋ฉด String Type์œผ๋กœ ํ‚ค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ํ‚ค์˜ ์ฒ˜์Œ๊ณผ ๋์— - - -Private Key - - -์™€ ๊ฐ™์€ ํƒœ๊ทธ๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

3) derRepresentation

Creates a P-256 private key for signing from a Distinguished Encoding

ํŠน์ •ํ•œ ํƒœ๊ทธ ๋ฐ ๊ธธ์ด์ •๋ณด๋ฅผ ํฌํ•จํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ง๋ ฌํ™” ํ•ด์„œ ์ €์žฅํ•œ๋‹ค (์‚ฌ์‹ค ์ •ํ™•ํ•œ ์˜๋ฏธ๋Š” ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค)

์‚ฌ์‹ค derRepresentation๊ณผ x963Representation์ด ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š”์ง€๋Š” ๋ชจ๋ฅด์ง€๋งŒ Data Type์„ base64String ์ด๋‚˜ hexString์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ด๋ฏธ ๊ตฌํ˜„๋œ ๋ถ€๋ถ„๊ณผ ๊ธธ์ด๋ฅผ ๋น„๊ตํ•˜๋ฉด ์–ด๋–ค Representation์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


ECDSA ํ‚ค ์ƒ์„ฑ ๋ฐ ์ €์žฅ์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ฉด,

  • Private Key, Public Key๋Š” pair๋กœ ์ƒ์„ฑ๋˜๋ฉฐ Private Key๋ฅผ ํ†ตํ•ด์„œ Public Key๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ‚ค ์ƒ์„ฑ์‹œ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ Representation์ด ์žˆ๋Š”๋ฐ base64String, hexString ๋“ฑ์œผ๋กœ ๋ณ€ํ™˜ํ•ด ์ด๋ฏธ ๊ตฌํ˜„๋œ ๊ณณ๊ณผ ๊ธธ์ด๋ฅผ ๋น„๊ตํ•ด์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.
  • Private Key๋Š” ๋ณดํ†ต KeyChain์„ ํ†ตํ•ด์„œ ์ €์žฅํ•˜๊ฒŒ ๋˜๋Š”๋ฐ rawRepresentation์„ ํ†ตํ•ด์„œ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์ €์žฅ์€ rawRepresentation์œผ๋กœ ํ•œ๋‹ค

Xib์™€ Nib

Xib์™€ Nib

์Šคํ† ๋ฆฌ๋ณด๋“œ์˜ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์™€ Custom View์˜ xibํŒŒ์ผ์ด ์ปดํŒŒ์ผ ์ดํ›„์— nibํŒŒ์ผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋Š”๋ฐ xib์™€ nib์€ ๋ฌด์—‡์ด ๋‹ค๋ฅธ๊ฒƒ์ผ๊นŒ?

Nib(=NeXTSETP Interface Builder)

Untitled 4

https://dalgonakit.tistory.com/82

  • ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ํด๋ž˜์Šค๋“ค์„ ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•ํƒœ์˜ ์••์ถœ ํŒŒ์ผ๋กœ ์ €์žฅ

Xib(=Xcode Interface Builder)

Untitled 5
  • ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ํด๋ž˜์Šค๋“ค์„ XML ํ˜•ํƒœ๋กœ ์ €์žฅ

๋‘ ํŒŒ์ผ์ด ์ƒ๊ธด ํ˜•ํƒœ๋ฅผ ๋ณด๋ฉด ํ™•์‹คํ•˜๊ฒŒ ์ฐจ์ด๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. Nib์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•ํƒœ๋กœ Xib๋Š” XML ํ˜•ํƒœ๋กœ Interface Builder๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ๋‹ค.


Xib ํŒŒ์ผ์„ ์ปดํŒŒ์ผ ํ•˜๋ฉด ๊ฒฐ๊ตญ NibํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋Š”๋ฐ ์™œ Xcode์—์„œ๋Š” Xib ํŒŒ์ผ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋„๋ก ์ง€์›ํ•˜๊ณ  ์žˆ์„๊นŒ?

์ด์œ ๋Š” ๋ฒ„์ „๊ด€๋ฆฌ์— ์žˆ๋‹ค. ๋ฌผ๋ก  ์Šคํ† ๋ฆฌ๋ณด๋“œ๋‚˜ Xib๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์—์„œ ๋ฒ„์ „๊ด€๋ฆฌ๊ฐ€ ๋ถˆํŽธํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์ฝ๊ณ  ์ „ํ˜€ ์ดํ•ดํ•˜๊ธฐ ํž˜๋“  ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•ํƒœ์˜ ์†Œ์Šค์ฝ”๋“œ ๋ณด๋‹ค๋Š” xml ํ˜•ํƒœ๋กœ ๋ฒ„์ „๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š”๊ฒŒ ๋” ํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

(๊ทธ๋ฆฌ๊ณ  Xcode์—์„œ๋Š” XibํŒŒ์ผ์„ xml์ด ์•„๋‹Œ ๊ทธ๋ž˜ํ”ฝ ํ˜•ํƒœ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๊ณ  ์žˆ๋‹ค)

์ œ๋„ค๋ฆญ ํƒ€์ž…

์ œ๋„ค๋ฆญ ํƒ€์ž…

Type Parameter

์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค๋ณด๋ฉด ํ•จ์ˆ˜๊ณผ ๊ฐ™์ด <>๋กœ ๊ฐ์‹ธ์ง„ ํ˜•ํƒœ๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ T๋Š” ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์–ด๋–ค ํƒ€์ž…์˜ โ€˜์ด๋ฆ„'์„ ์˜๋ฏธํ•œ๋‹ค.

func swap<T>(_ a: inout T, _ b: inout T) {
	let temp = a
	a = b
	b = temp
}

๋ง๊ทธ๋Œ€๋กœ ์–ด๋–ค โ€˜ํƒ€์ž…โ€™ ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ํ•ด๋‹น ํƒ€์ž…์ด ์–ด๋–ค ํƒ€์ž…์ธ์ง€ ๊ฒฐ์ •๋˜์ง€ ์•Š๊ณ  ๋Ÿฐํƒ€์ž„ ๊ณผ์ •์—์„œ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•œ๋‹ค

์˜ˆ๋ฅผ ๋“ค์–ด์„œ, C++ STL์— ์žˆ๋Š” Stack์„ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์ด์šฉํ•ด์„œ ํƒ€์ž…์— ๋ฌด๊ด€ํ•œ Stack์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

struct Stack<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}

Type Constraint

์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋Š”

struct TextFieldCustomViewWrapper<KeyboardView: View>: UIViewRepresentable {
}

KeyboardView ๋ผ๋Š” ํƒ€์ž…ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ KeyboardView๋Š” View ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๋Š” ์–ด๋–ค ํƒ€์ž…

์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํŠน์ • ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•ด์•ผ๋งŒ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํƒ€์ž… ์ œ์•ฝ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

Swift ์˜ Dictionary ๊ตฌ์กฐ์ฒด๋ฅผ ๋“ค์—ฌ๋‹ค ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํƒ€์ž… ์ œ์•ฝ์ด ๊ฑธ๋ ค์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@frozen struct Dictionary<Key, Value> where Key : Hashable

์ฆ‰ Key๊ฐ€ Hashable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ํƒ€์ž…์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ์•ฝ์ด ๊ฑธ๋ ค์žˆ๋‹ค.

Associated Type

protocol Publisher {
  associatedtype Output
  associatedtype Failure : Error
  func receive<S>(subscriber: S) 
		where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}

ํ”„๋กœํ† ์ฝœ์„ ๋ณด๋‹ค๋ณด๋ฉด associatedType์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. associated Type ์ด๋‹ˆ๊นŒ ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒ๊ฐํ•˜๋Š” Type์ž„์„ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ๋ณด๋ฉด ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

protocol BranProtocol {
	associatedtype MyType
	var name: MyType { get }
}

struct Bran: BranProtocol {
	var name: String {
		return "Sangwon"
	}
}

BranProtocol์„ ์ฑ„ํƒํ•˜๋ฉด MyType์˜ name์„ ์ •์˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ String ํƒ€์ž…์ด์™ธ์—๋„ ๋‹ค๋ฅธ ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ name์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๋•Œ ์œ„์™€ ๊ฐ™์ด associatedtype์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

(ํ”„๋กœํ† ์ฝœ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์œผ๋กœ ์ƒ๊ฐ!)

์œ„์˜ ์ œ๋„ค๋ฆญ์—์„œ ๋ดค๋˜ ์˜ˆ์ œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์—ฐ๊ด€ํƒ€์ž…์—๋„ ํ”„๋กœํ† ์ฝœ์„ ํ†ตํ•ด์„œ ์ œ์•ฝ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

[CS] WebSocket, Socket.io

WebSocket

WebSocket ๊ณผ Socket.io

์ง€๊ธˆ๊นŒ์ง€ ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ํ•ด๋ณธ ํ”„๋กœ์ ํŠธ๊ฐ€ ํ•˜๋‚˜๋ฐ–์— ์—†์–ด ์ •ํ™•ํ•˜๊ฒŒ ๊ณต๋ถ€ํ•˜์ง€ ๋ชปํ–ˆ๋Š”๋ฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‘˜์€ ๋‹ค๋ฅด๋‹ค.

๊ถ๊ธˆํ•œ๊ฒƒ

  • ๊ทธ๋Ÿผ ์ € ๋‘˜์˜ ์ฐจ์ด๋Š” ์„œ๋ฒ„ ๊ตฌํ˜„์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”๊ฒƒ์ธ๊ฐ€? (์„œ๋ฒ„๊ฐ€ socket.io ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด์•ผ ํด๋ผ์ด์–ธํŠธ๋„ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ธ๊ฐ€?)
  • StarScream ๊ณผ socket.io-swift ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฐจ์ด๋„ ์œ„์™€ ๊ฐ™์€ ๊ธฐ์ค€์œผ๋กœ ์„ ํƒํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ธ๊ฐ€?
  • WebSocket ping, pong, hand shake์˜ ์˜๋ฏธ

WebSocket

์„œ๋กœ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ๋ผ๋ฆฌ ์†Œํ†ตํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋กœํ† ์ฝœ

  • HTML5 ์›น ํ‘œ์ค€ ๊ธฐ์ˆ 
  • ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฉฐ ํ†ต์‹ ํ•  ๋•Œ ์•„์ฃผ ์ ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•จ
  • ์ด๋ฒคํŠธ๋ฅผ ๋‹จ์ˆœํžˆ ๋“ฃ๊ณ , ๋ณด๋‚ด๋Š” ๊ฒƒ๋งŒ ๊ฐ€๋Šฅํ•จ

Socket.io

์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ์œ„ํ•ด ์›น์†Œ์ผ“ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ํ‘œ์ค€ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ฉฐ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž„
  • ์†Œ์ผ“ ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ fallback์„ ํ†ตํ•ด ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์•Œ์•„์„œ ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ์™€ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•จ
  • ๋ฐฉ ๊ฐœ๋…์„ ์ด์šฉํ•ด ์ผ๋ถ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ๊ฐ€๋Šฅํ•จ

๋‹จํŽธ์ ์œผ๋กœ ๋ดค์„ ๋•Œ, ์šฐ๋ฆฌ๊ฐ€ Socket ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ์–ป์œผ๋ ค๋Š” ์ด์ ์ด(์–‘๋ฐฉํ–ฅ ํ†ต์‹ , ์‹ค์‹œ๊ฐ„ ๋„คํŠธ์›Œํ‚น) ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„์Šทํ•˜๊ฒŒ ์ƒ๊ฐํ–ˆ๋˜๊ฒƒ ๊ฐ™๋‹ค.

์›น์†Œ์ผ“์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ด์ „์— ์–‘๋ฐฉํ–ฅ๊ณผ ์‹ค์‹œ๊ฐ„ ๋„คํŠธ์›Œํ‚น์„ ์œ„ํ•ด์„œ๋Š” ์ผ์ • ์ฃผ๊ธฐ๋กœ API Call์„ ์ด์„œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” Polling ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ๋‹จ์ˆœํ•˜๊ฒŒ ์ƒ๊ฐํ•ด๋ด๋„ ์„œ๋ฒ„์— ๋ถ€ํ•˜๊ฐ€ ์‹ฌํ•ด์ง„๋‹ค

์ด๋Ÿฐ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ๊ฒƒ์ด WebSocket์ด๊ณ  HTML5์˜ ๊ธฐ์ˆ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ž˜๋œ ๋ฒ„์ „์˜ ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Socket.io๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค


1)

Socket.io๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ js๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๊ฐœ๋ฐœ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์„œ๋ฒ„๋Š” socket.io๋ฅผ ํด๋ผ์ด์–ธํŠธ๋Š” socket.io-client ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์„œ๋ฒ„๊ฐ€ socket.io๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐœ๋ฐœ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ ๋‹จ์—์„œ๋Š” ๋‹น์—ฐํžˆ socket.io-client๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

2)

1๋ฒˆ๊ณผ ์ผ๋งฅ์ƒํ†ตํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค. ๋ฌผ๋ก  ์„œ๋ฒ„์—์„œ socket.io๋กœ ๋งŒ๋“ค์—ˆ์„ ๋•Œ, ํด๋ผ์ด์–ธํŠธ์—์„œ URLSessionSocket์ด๋‚˜ StarStream์„ ์ด์šฉํ•ด์„œ ์†Œ์ผ“ ํ†ต์‹ ์„ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ socket.io๋งŒ์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ• ์ง€๋Š” ๋ฏธ์ง€์ˆ˜์ด๋ฉฐ socket.io๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŽธ์ด ๊ตฌํ˜„ ๋‚œ์ด๋„๋„ ๋” ๋‚ฎ๋‹ค.

๋”ฐ๋ผ์„œ ์„œ๋ฒ„์— ๋งž์ถฐ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค.

Swift WebSockets: Starscream or URLSession in 2021?

StarScream๊ณผ URLSessionSocket์€ ์œ„์˜ ๊ธ€์„ ์ฝ์–ด๋ณด๊ณ  ์„ ํƒํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์š”์•ฝํ•˜๋ฉด URLSession์€ Apple์—์„œ ๊ณ„์†ํ•ด์„œ ์ง€์›ํ•ด์ฃผ๊ณ  ์žˆ๊ณ  Starscream์€ ์ตœ๊ทผ ์—…๋ฐ์ดํŠธ๊ฐ€ ์—†๋‹ค

URLSessionSocket์ด iOS13๊ณผ ํ•จ๊ป˜ ๋‚˜์˜จ ๊ธฐ์ˆ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์†Œ๋ฒ„์ „์ด iOS13 ์ด์ƒ์ด๋ผ๋ฉด URLSession์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋‚˜์˜์ง€ ์•Š์€ ์„ ํƒ์ด๋‹ค (๋ฌผ๋ก  receive๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ ์กด์žฌ)

3)

์‚ฌ์‹ค ping, pong์ด hand shake ๊ณผ์ • ์ค‘ ์ผ๋ถ€๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์—ˆ๋Š”๋ฐ ๋‘˜์€ ์™„์ „ ๋‹ค๋ฅด๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์†Œ์ผ“์œผ๋กœ ์—ฐ๊ฒฐ๋˜๊ณ  ๋‚œ ์ดํ›„์— ๋‘˜ ์‚ฌ์ด์— ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ ์†ก, ์ˆ˜์‹ ์ด ์—†๋Š” ์ƒํƒœ๊ฐ€ ๊ธธ์–ด์ง€๋ฉด ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์™€์˜ ์—ฐ๊ฒฐ์„ ๋Š์–ด๋‚ธ๋‹ค (idle timeout)

์ด๋Ÿฐ ์—ฐ๊ฒฐ ์ข…๋ฃŒ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ ์„œ๋ฒ„ or ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋กœ ping, pong์„ ์ฃผ๊ณ  ๋ฐ›์œผ๋ฉฐ ์—ฐ๊ฒฐ์„ ํ™•์ธํ•œ๋‹ค.

ํ•ธ๋“œ ์‰์ดํฌ ๊ณผ์ •์€ ์†Œ์ผ“ ํ†ต์‹ ์€ ๊ฒฐ๊ตญ TCP ํ”„๋กœํ† ์ฝœ์„ ๋”ฐ๋ฅด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•  ๋•Œ์™€ ์ข…๋ฃŒ๋  ๋•Œ, ํ•ธ๋“œ ์‰์ดํฌ๋ฅผ ํ†ตํ•ด์„œ ๋ชจ๋‘ ๋ฐ์ดํ„ฐ๋ฅผ ์†ก,์ˆ˜์‹  ํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด์žˆ์Œ์„ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํžŒ๋‹ค.

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ - 01

Concurrency

๋ฏธ๋ฃจ๊ณ  ๋ฏธ๋ฃจ๋˜ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด์„œ ๋“œ๋””์–ด ํ•œ๋ฒˆ ์ž์„ธํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค!
๊ฐ•์˜์™€ ๋ธ”๋กœ๊ทธ๋ฅผ ํ™œ์šฉํ•ด์„œ ํœ˜๋ฐœ์„ฑ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๋ฏธ๋ž˜์˜ ๋‚˜๋ฅผ ์œ„ํ•ด ์ตœ๋Œ€ํ•œ ์ž์„ธํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ’€์–ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค

แ„ƒแ…กแ„‹แ…ฎแ†ซแ„…แ…ฉแ„ƒแ…ณ

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ์™œ ํ•„์š”ํž๋ผ?

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋‹จ์ˆœํ•˜๋‹ค. ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ด์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ๋Š๋ฆฌ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ํ†ตํ•ด ๋ถˆ๋Ÿฌ์˜จ ๊ฐ’์„ ํ…Œ์ด๋ธ” ๋ทฐ์— ๋ณด์—ฌ์ค„ ๋•Œ ์Šคํฌ๋กค์„ ํ•˜๋ฉด ์•ฑ์ด ๋š๋š ๋Š๊ธฐ๋Š” ํ˜„์ƒ์ด๋‹ค.

๊ทธ๋Ÿผ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ด์šฉํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๊ฑธ๊นŒ?
๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒƒ์€ ์‹ค์ƒํ™œ๋กœ ์˜ˆ๋ฅผ๋“ค๋ฉด ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™๋‹ค

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 6 58 25

๋ถˆ์Œํ•œ ๋…ธ๋™์ž ํ•œ๋ช…๋งŒ ์—ด์‹ฌํžˆ ์ผ์„ ํ•˜๊ณ  ์žˆ๋‹ค. ๋‚˜ ๋ชป์ฐธ์•„!!!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 7 26 48

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ํ•œ ๋…ธ๋™์ž์—๊ฒŒ ์ž‘์—…์ด ๋ชฐ๋ฆฌ์ง€ ์•Š๊ณ  ์ด๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ๋™์‹œ์— ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์—…์„ ๋ถ„๋ฐฐํ•  ์ˆ˜ ์žˆ๋‹ค

๊ทธ๋Ÿผ ์“ฐ๋ ˆ๋“œ(๋…ธ๋™์ž)์—๊ฒŒ ์ž‘์—…์„ ์ผ์ผ์ด ์ง์ ‘ ๋ถ„๋ฐฐํ•ด์•ผ ํ•˜๋‚˜์š”?

์ •๋ง ๊ฐ์‚ฌํ•˜๊ฒŒ๋„ ์šฐ๋ฆฌ๋Š” ์ง์ ‘์ ์œผ๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , iOS์—์„œ ์ œ๊ณตํ•˜๋Š” ๋Œ€๊ธฐํ–‰๋ ฌ(Queue)์— ๋ณด๋‚ด๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 8 15 53

  • GCD(=Dispatch Queue)
  • Operation Queue

iOS์—์„œ ์ œ๊ณตํ•˜๋Š” ๋Œ€๊ธฐํ–‰๋ ฌ์€ ํฌ๊ฒŒ ์œ„์˜ ๋‘ ์ข…๋ฅ˜์ด๋‹ค!

์šฐ๋ฆฌ๋Š” ์ž‘์—…๋“ค์„ ์œ„์˜ ํ์— ๋„ฃ์–ด์ฃผ๋ฉด ๊ฐ ํ์˜ ํŠน์„ฑ์— ๋งž๊ฒŒ OS์—์„œ ๊ด€๋ฆฌํ•ด์ค€๋‹ค!!

DispatchQueue.global().async {
  print("Task1")
  print("----------Task1---------")
}

์‚ฌ์šฉ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉด
DispatchQueue(ํ์— ๋ณด๋‚ธ๋‹ค.).global()(global ์ด๋ผ๋Š” ํ์—).async (๋น„๋™๊ธฐ์ ์œผ๋กœ){ ์ดํ•˜ ์ž‘์—…์„ } ์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฒ˜์Œ ๊ณต๋ถ€ํ•  ๋•Œ ๋‚˜๋ฅผ ๋ฉ˜๋ถ•์— ๋น ํŠธ๋ ธ๋˜ ๋™๊ธฐ/๋น„๋™๊ธฐ ํ‚ค์›Œ๋“œ๊ฐ€ ๋ณด์ด๋Š”๋ฐ ์ฒœ์ฒœํžˆ ํ•˜๋‚˜์”ฉ ํ’€์–ด๊ฐ€๋ณด์ž!

๋™๊ธฐ์™€ ๋น„๋™๊ธฐ

๋†€๋ž๊ฒŒ๋„ ์ด์ „์— ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ–ˆ๋˜ ์ ์ด ์žˆ๋‹ค. ๋‚ด ๊ธฐ์–ต ์–ด๋””๊ฐ„๊ฑฐ์•ผ? ๐Ÿคฆ

์œ„์™€ ๊ฐ™์€ ๊ทธ๋ฆผ์„ ์˜ˆ์ œ๋กœ ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ๋ฅผ ์ดํ•ดํ•ด๋ณด์ž!
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 9 00 50

๋…ธ๋™๋ ฅ ์ฐฉ์ทจ์— ํ™”๊ฐ€ ๋‚˜๋ฒ„๋ฆฐ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ Task1 ์„ ํ์— ๋ณด๋‚ธ ์ƒํ™ฉ์ด๋‹ค.
ํ•˜์ง€๋งŒ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•ด์•ผํ•˜๋Š” ์ž‘์—…๋“ค(Task2, Task3, Task4)๊ฐ€ ์—ฌ์ „ํžˆ ๋‚จ์•„์žˆ์ฃ ?

์ด๋•Œ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•ด์•ผํ•  ํ–‰๋™์œผ๋กœ ์˜ฌ๋ฐ”๋ฅธ๊ฒƒ์€?

  • ์•„ ๋ชฐ๋ž‘ Task1์ด ์™„๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ์‰ด๋ž˜ (๋™๊ธฐ)
  • ์–ด๋ฆผ๋„ ์—†์ง€ ๋ฐ”๋กœ Task2 ์‹œ์ž‘ (๋น„๋™๊ธฐ)

์ด๊ฒŒ ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ์˜ ๊ฐœ๋…์ด๋‹ค.

  • ๋™๊ธฐ๋Š” ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ํ๋กœ ๋ณด๋‚ธ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค
  • ๋น„๋™๊ธฐ๋Š” ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ํ๋กœ ๋ณด๋‚ด๊ณ  ์ž‘์—… ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ž‘์—…์„ ์‹œ์ž‘ํ•œ๋‹ค.

์‚ฌ์‹ค ์ฒ˜์Œ ๊ณต๋ถ€ํ•  ๋•Œ ๋น„๋™๊ธฐ์™€ ๋™๊ธฐ ๊ทธ๋ฆฌ๊ณ  ๋™์‹œ์™€ ์ง๋ ฌ์˜ ๊ฐœ๋…์ด ๋’ค์ฃฝ๋ฐ•์ฃฝ ์„ž์ด๋ฉด์„œ ์œ„์˜ ๊ฐœ๋…์ด ๋ช…ํ™•ํ•˜๊ฒŒ ํ™•๋ฆฝ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ ๊ธฐ์–ตํ•˜๋˜ ์ง€์‹๋“ค์„ ๋ฐฐ์ œํ•˜๊ณ  ๋”ฑ ์ €๋ ‡๊ฒŒ ์ดํ•ดํ•˜์ž!

์ง๋ ฌ๊ณผ ๋™์‹œ (Serial & Concurrent)

์ง๋ ฌ๊ณผ ๋™์‹œ๋Š” ํ์˜ ํŠน์„ฑ์— ๊ด€ํ•œ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์•ž์„œ iOS์—์„œ ์ œ๊ณตํ•˜๋Š” ํ๋Š” ํฌ๊ฒŒ GCD, Operation Queue 2๊ฐœ๋กœ ๋‚˜๋‰œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ 2๊ฐœ์˜ ํ ๋ชจ๋‘ Serial, Concurrent๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Serial Queue์— ์—ฌ๋Ÿฌ ์ž‘์—…๋“ค์„ ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํ๋Š” ์ž‘์—…๋“ค์„ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค
Concurrent Queue์— ์—ฌ๋Ÿฌ ์ž‘์—…๋“ค์„ ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ํ๋Š” ์ž‘์—…๋“ค์„ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค

์—ฌ๊ธฐ์„œ ์˜๋ฌธ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค

  • ์•„๋‹ˆ.. Serial Queue์— ๋น„๋™๊ธฐ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฌด์Šจ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”๊ฑฐ์•ผ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 6 58 25

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 10 30 58

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 10 32 43

Serial Queue์— Task1,2,3๋ฅผ async ํ•˜๊ฒŒ ๋ณด๋ƒˆ๋‹ค.
asyncํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋Š” Task4๋ฅผ ๋ฐ”๋กœ ์‹คํ–‰ํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๊ณ , Serial Queue๋Š” ์ž‘์—…๋“ค์„ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ๋žญ์ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ์— ์žˆ๋˜ ๋ชจ๋“  ์ž‘์—…๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

  • ์•„๋‹ˆ.. Concurrent Queue์— ๋™๊ธฐ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฌด์Šจ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”๊ฑฐ์•ผ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 6 58 25

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 10 39 07

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-20 แ„‹แ…ฉแ„’แ…ฎ 10 41 05

Concurrent Queue์— Task 1,2,3๋ฅผ syncํ•˜๊ฒŒ ๋ณด๋ƒˆ๋‹ค. Concurrent Queue์— ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ์— ๋“ค์–ด์˜จ ์ž‘์—…๋“ค์€ ๋™์‹œ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋˜๊ณ  sync ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ์— ๋“ค์–ด๊ฐ”๋˜ ์ž‘์—…๋“ค์ด ๋ชจ๋‘ ์™„๋ฃŒ๋˜์–ด์•ผ task4๊ฐ€ ์‹คํ–‰๋œ๋‹ค


ํ•ญ์ƒ ํ—ท๊ฐˆ๋ ธ๋˜ ๊ฐœ๋…์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ •ํ™•ํ•˜๊ฒŒ ์งš์–ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์ด์˜€๋‹ค.
Serial/Concurrent ์™€ Sync/Async ๋Š” ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋‹ค!!

ํ•ด๋‹น ๋‚ด์šฉ์€ ์•จ๋Ÿฐ๋‹˜์˜ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ธ€ ์ž…๋‹ˆ๋‹ค.

๊ณ„์†ํ•ด์„œ ์ •๋ฆฌ ํ•  ์˜ˆ์ •์ด๊ณ  ํ‹€๋ฆฌ๊ฑฐ๋‚˜ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”!

[weak self]

weak self ์— ๋Œ€ํ•˜์—ฌ - 1

๊ฐ„๋žตํ•˜๊ณ  ์ดํ•ดํ•œ ๋‚ด์šฉ ์œ„์ฃผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  ์ฃผ๋ง์— ์˜ˆ์ œ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ๋” ์ƒ์„ธํžˆ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ WWDC21 ์ฐธ๊ณ ํ•˜๊ธฐ
์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ ๋ธ”๋กœ๊ทธ

Swift๋Š” ARC๋ฅผ ํ†ตํ•ด์„œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ ์นด์šดํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  0์ด ๋˜๋ฉด ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
ํ•˜์ง€๋งŒ ๋‘๊ฐœ ์ด์ƒ์˜ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๋ฉด ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ผ์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํ˜„์ƒ์ด ์ผ์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ํ˜„์ƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” weak๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ํƒˆ์ถœ ํด๋กœ์ €์—์„œ [weak self]๋ฅผ ์ž์ฃผ ์ ‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํƒˆ์ถœ ํด๋กœ์ €์—์„œ ๊ฐ’์„ ์บก์ฒ˜ํ•˜๋Š” ๊ณผ์ •์— ๋ช…์‹œ์ ์œผ๋กœ self๋ฅผ ์ž‘์„ฑํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ ์ด๋•Œ self์— ๋Œ€ํ•œ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

[SwiftUI] List Item์„ NavigationLink๋กœ ๋งŒ๋“ค ๊ฒฝ์šฐ

LazyVStack - NavigationLink

LazyVstack์•ˆ์— NavigationLink๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ•œ ๋ฒ„๊ทธ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

Simulator Screen Recording - iPhone 14 Pro - 2023-01-20 at 20 37 32

ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฒฐ๊ณผ๊ฐ’์— ๋”ฐ๋ผ Media List๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ๊ฐ Cell์„ ํด๋ฆญํ•˜๋ฉด DetailView๋กœ Push ๋˜๊ณ  ์žˆ๋Š” ํ˜•ํƒœ์˜ ์•ฑ์ด๋‹ค.

struct MediaListView: View {
  @StateObject
  var viewModel: MediaListViewModel

  let appContainer: AppContainer

  var body: some View {
    NavigationView {
      ScrollView {
        LazyVStack {
          ForEach(viewModel.output.medias, id: \.id) { media in
            NavigationLink(
              destination: {
                NavigationLazyView(
                  MediaDetailView(
                    viewModel: appContainer.mediaDetailViewModel(media)
                  )
                )
              },
              label: {
                MediaListItemView(media: media)
              }
            )
          }
        }
        .padding(.top, 20)
        .padding([.leading, .trailing], 12)
      }
      .navigationTitle("TV Search")
      .navigationBarTitleDisplayMode(.inline)
      .searchable(text: $viewModel.input.searchMediaSub.value)
    }
  }
}

SwiftUI์˜ NavigationLink๋Š” ์‚ฌ์šฉ์ž๊ฐ€ pushํ•˜๊ธฐ ์ด์ „๋ทฐ์—์„œ๋„ push๋  ๋ทฐ๋ฅผ ๋ฏธ๋ฆฌ loadํ•˜๊ณ  ์žˆ๋Š” ๋ฌธ์ œ์ (?)์ด ์žˆ๋Š”๋ฐ ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ ์ž push๋˜๋Š” ์‹œ์ ์—์„œ ๋ทฐ๊ฐ€ ๊ทธ๋ ค์งˆ ์ˆ˜ ์žˆ๋„๋ก NavigaitonLazyView๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ๊ธฐ์กด์— ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” cell์„ ํด๋ฆญํ•˜๋Š” ์‹œ์ ์— ์‚ฌ์šฉ์ž๊ฐ€ ํ‚ค๋ณด๋“œ๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด ์ž๋™์œผ๋กœ navigation pop์ด ๋˜๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.

์ž…๋ ฅ๊ฐ’์ด ๋ณ€ํ™”ํ•จ์— ๋”ฐ๋ผ์„œ ๊ธฐ์กด์˜ list๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ cell์ด ์‚ฌ๋ผ์ง€๋ฉด์„œ navigationLink๋„ ์‚ฌ๋ผ์ ธ ๋ฒ„๋ฆฐ๊ฒƒ์ด๋‹ค!

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?

์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” list์˜ cell์ด navigationLink๋ผ๋Š” View๋กœ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ List์˜ cell Item ์ž์ฒด๊ฐ€ navigationLink๊ฐ€ ๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

import SwiftUI

struct MediaListView: View {
  @StateObject
  var viewModel: MediaListViewModel

  let appContainer: AppContainer

  var body: some View {
    NavigationView {
      ScrollView {
        LazyVStack {
          // Empty View
          NavigationLink(
            isActive: $viewModel.output.isNavigationShow,
            destination: {
              if let media = viewModel.output.selectedMedia {
                NavigationLazyView(
                  MediaDetailView(
                    viewModel: appContainer.mediaDetailViewModel(media)
                  )
                )
              }
            },
            label: { }
          )
          // List Cell Item
          ForEach(viewModel.output.medias, id: \.id) { media in
            MediaListItemView(media: media)
              .wrapToButton { viewModel.action(.navigationTapped(media)) }
          }
        }
        .padding(.top, 20)
        .padding([.leading, .trailing], 12)
      }
      .navigationTitle("TV Search")
      .navigationBarTitleDisplayMode(.inline)
      .searchable(text: $viewModel.input.searchMediaSub.value)
    }
  }
}

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค. List์™ธ๋ถ€์— Empty View Label์„ ๊ฐ€์ง€๋Š” NavigationLink๋ฅผ ๋งŒ๋“ค๊ณ , ํ•ด๋‹น NavigationLink๋ฅผ ํ†ตํ•ด์„œ ํ™”๋ฉด์ „ํ™˜์„ ํ•˜๋ฉด๋œ๋‹ค.

์ฝ”๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ๋ณด์ž. ๊ธฐ์กด์—๋Š” List์˜ Item ์ž์ฒด๊ฐ€ NavigationLink์˜€์ง€๋งŒ ๋‹จ์ˆœํžˆ Button ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋ฒ„ํŠผ์œผ๋กœ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

import Combine
import Foundation

final class MediaListViewModel: ViewModelType {
  private let searchMediaUsecase: SearchMediaUseCase

  struct Input {
    var searchMediaSub = BindingSubject<String>(value: "")
    fileprivate let searchButtonSub = PassthroughSubject<Void, Never>()
    fileprivate let navigationSub = PassthroughSubject<Media, Never>()
  }

  enum Action {
    case searchButtonTapped
    case navigationTapped(Media)
  }

  func action(_ action: Action) {
    switch action {
    case .searchButtonTapped:
      input.searchButtonSub.send()
    case .navigationTapped(let media):
      input.navigationSub.send(media)
    }
  }

  struct Output {
    var medias: [Media] = []
    var isNavigationShow: Bool = false
    var selectedMedia: Media?
  }

  var input = Input()
  @Published var output = Output()
  var cancellables = Set<AnyCancellable>()

  init(searchMediaUsecase: SearchMediaUseCase) {
    self.searchMediaUsecase = searchMediaUsecase
    transform()
  }

  func transform() {
    input.searchMediaSub.subject
      .debounce(for: 0.5, scheduler: RunLoop.main)
      .flatMap { [weak self] search -> AnyPublisher<MediaPage, Never> in
        guard let self = self else {
          return Just(MediaPage(page: -1, totalPages: -1, medias: [])).eraseToAnyPublisher()
        }
        return self.searchMediaUsecase.tvExcute(query: search, page: 1)
          .replaceError(with: MediaPage(page: -1, totalPages: -1, medias: []))
          .eraseToAnyPublisher()
      }
      .map { $0.medias }
      .sink(receiveValue: { [weak self] in
        guard let self = self else { return }
        self.output.medias = $0
      })
      .store(in: &cancellables)

    input.navigationSub
      .sink(receiveValue: { [weak self] in
        guard let self = self else { return }
        self.output.selectedMedia = $0
        self.output.isNavigationShow = true
      })
      .store(in: &cancellables)
  }
}

๋ทฐ๋ชจ๋ธ์˜ ํ”„๋ ˆ์  ํ…Œ์ด์…˜ ๋กœ์ง์„ ํ™•์ธํ•ด๋ณด๋ฉด, ์‚ฌ์šฉ์ž๊ฐ€ DetailView๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด์„œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ๋ฒ„ํŠผ์„ ๊ทธ๋ฆด ๋•Œ ์‚ฌ์šฉ๋˜์—ˆ๋˜ Media๋ฅผ subject๋ฅผ ํ†ตํ•ด ๋„˜๊ฒจ์ฃผ๊ณ  navigationLink์˜ isActive๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.
Simulator Screen Recording - iPhone 14 Pro - 2023-01-20 at 21 17 30

๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ „์ฒด ํ”„๋กœ์ ํŠธ๋Š” ์—ฌ๊ธฐ์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 4

HTTP - Method

ํด๋ผ์ด์–ธํŠธ ๊ฐœ๋ฐœ์ž๋กœ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŒ๋“ค์–ด์ค€ API๋ฅผ ์“ฐ๋ฉด์„œ ๋Œ€์ถฉ ์•Œ๊ณ  ์žˆ๋˜ HTTP Method๋ฅผ ์ œ๋Œ€๋กœ ์ •๋ฆฌํ•ด๋ณด์ž


API ์„ค๊ณ„

  • ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ
  • ํšŒ์› ์กฐํšŒ
  • ํšŒ์› ๋“ฑ๋ก
  • ํšŒ์› ์ˆ˜์ •
  • ํšŒ์› ์‚ญ์ œ

์œ„์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ API URL ๋งŒ๋“ค์–ด๋‹ฌ๋ผ๋Š” ์š”์ฒญ์„ ๋ฐ›์•˜์„ ๋•Œ URL์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ• ๊นŒ?

  • ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ /read-member-list
  • ํšŒ์› ์กฐํšŒ /read-member-by-id
  • ํšŒ์› ๋“ฑ๋ก /create-member
  • ํšŒ์› ์ˆ˜์ • /update-member
  • ํšŒ์› ์‚ญ์ œ /delete-member

์œ„์™€ ๊ฐ™์ด ๋„ค์ด๋ฐ์„ ํ†ตํ•ด์„œ URL์„ ์„ค๊ณ„ํ•˜๋ฉด ์–ด๋–จ๊นŒ? URL ํ˜•ํƒœ๋งŒ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋™์ž‘ ์ž์ฒด๋ฅผ ์•Œ ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ ๊ดœ์ฐฎ์ง€ ์•Š์„๊นŒ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด NO์ด๋‹ค. URI๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํฌ์ธํŠธ๋Š” ๋ฆฌ์†Œ์Šค ์‹๋ณ„์ด๋‹ค.

์œ„์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์—์„œ ํšŒ์› ์— ๋Œ€ํ•œ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ  ํšŒ์› = ๋ฆฌ์†Œ์Šค์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํšŒ์›์ด๋ผ๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ URI์— ๋งคํ•‘ ์‹œ์ผœ์„œ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค.

  • ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ /members
  • ํšŒ์› ์กฐํšŒ /members/{id}
  • ํšŒ์› ๋“ฑ๋ก /members/{id}
  • ํšŒ์› ์ˆ˜์ • /members/{id}
  • ํšŒ์› ์‚ญ์ œ /members/{id}

๊ทธ๋Ÿผ ํšŒ์› ์กฐํšŒ, ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ์™€ ๊ฐ™์€ ํ–‰์œ„๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•˜๋Š” ๊ฑธ๊นŒ?

โ†’ ์ด๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ด HTTP Method์ด๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜์ž๋ฉด

  • URI ์„ค๊ณ„์‹œ ์šฐ์„ ์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค์™€ ํ–‰์œ„๋ฅผ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•œ๋‹ค
  • ๋ฆฌ์†Œ์Šค๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก URI๋ฅผ ๋งŒ๋“ค๊ณ 
  • ํ–‰์œ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ URI์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์„ค๊ณ„ํ•œ๋‹ค

HTTP Method

  • GET

  • POST

  • PUT

  • PATCH

  • DELETE

  • HEAD

  • OPTIONS

  • CONNECT

  • TRACE

๋ฉ”์„œ๋“œ์˜ ์ข…๋ฅ˜๋Š” ์œ„์™€ ๊ฐ™๊ณ  ์•„๋ž˜ 4๊ฐœ๋Š” ํ•œ๋ฒˆ๋„ ๋ณธ์ ์ด ์—†์—ˆ๋Š”๋ฐ ์กด์žฌ ์ •๋„๋งŒ ์•Œ๊ณ  ๋„˜๊ธฐ๋ฉด ๋ ๊ฒƒ ๊ฐ™๋‹ค.


GET

  • ๋ฆฌ์†Œ์Šค ์กฐํšŒ
  • ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์‹œ query ํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉ
  • ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ์ด์šฉํ•ด์„œ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธธ ์ˆ˜๋„ ์žˆ์ง€๋งŒ HTTP ๋ฒ„์ „๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค.

POST

  • ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ
  • ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

POST๋Š” ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋“ฑ ๊ฑฐ์˜ ๋ชจ๋“  ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

PUT

  • ๋ฆฌ์†Œ์Šค๋ฅผ ์™„์ „ํžˆ ๋Œ€์ฒด(=๋ฎ์–ด์“ฐ๊ธฐ)
    • ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋Œ€์ฒด
    • ๋ฆฌ์†Œ์Šค๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ์†Œ์Šค ์œ„์น˜๋ฅผ ์•Œ๊ณ  URI๋ฅผ ์ง€์ •

์ด์ „ ๋ฉด์ ‘์—์„œ PUT, POST์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด์„œ ์งˆ๋ฌธ ๋ฐ›์€ ์ ์ด ์žˆ์—ˆ๋Š”๋ฐ ์ด์ œ ์ด๋ ‡๊ฒŒ ๋‹ต๋ณ€ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

๋‘˜ ๋‹ค ์„œ๋ฒ„์— ์–ด๋–ค ๋ฆฌ์†Œ์Šค๋ฅผ (๋Œ€์ฒด, ์ƒ์„ฑ) ํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ณตํ†ต์ ์ด ์žˆ์ง€๋งŒ POST์˜ ๊ฒฝ์šฐ URI์— ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์˜ ์œ„์น˜๋ฅผ ๋ชจ๋ฅด๊ณ  PUT์€ URI์— ํ•ด๋‹น ๋ฆฌ์†Œ์Šค ์œ„์น˜๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

POST/members
Content-Type: json
{
	"username": "young",
	"age": 20
}
// members/100์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ์ƒ์„ฑ

PUT/members/100
Content-Type: json
{
	"username": "young",
	"age": 20
}
// members/100๋ฅผ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋กœ ๋Œ€์ฒด

๊ทธ๋ฆฌ๊ณ  ์™„์ „ํžˆ ๋Œ€์ฒด ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ํ•ด๋‹น ์œ„์น˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์ผ๋ถ€๋ถ„๋งŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

// members/100(DB)
{
	"username": "young",
	"age": 20
}

PUT/members/100
Content-Type: json
{
	"age": 30
}
// members/100๋ฅผ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋กœ ๋Œ€์ฒด

// members/100(DB)
{
	"age": 30
}

์œ„์™€ ๊ฐ™์ด age์˜ ๊ฐ’๋งŒ ๋ถ€๋ถ„ ์ˆ˜์ •ํ•  ์ˆ˜๋Š” ์—†๊ณ  ์™„์ „ํžˆ ๋Œ€์ฒดํ•ด์„œ username์˜ ๊ฐ’์ด ์‚ฌ๋ผ์ง„๋‹ค.

PATCH

  • ๋ฆฌ์†Œ์Šค ๋ถ€๋ถ„ ๋ณ€๊ฒฝ
  • PATCH๊ฐ€ ์—†๋Š” HTTP์ธ ๊ฒฝ์šฐ POST๋ฅผ ์‚ฌ์šฉ

์œ„์˜ PUT์—์„œ ๋ถ€๋ถ„ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋˜ ๋ถ€๋ถ„์„ PATCH๋ฅผ ํ†ตํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

DELETE

  • ๋ฆฌ์†Œ์Šค ์ œ๊ฑฐ

HTTP Method ์†์„ฑ

  • ์•ˆ์ „: ํ˜ธ์ถœํ•ด๋„ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”์ง€?
  • ๋ฉฑ๋“ฑ: 1๋ฒˆ ํ˜ธ์ถœ๊ณผ n๋ฒˆ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์€์ง€?
  • ์บ์‹œ๊ฐ€๋Šฅ: ์‘๋‹ต ๊ฒฐ๊ณผ ๋ฆฌ์†Œ์Šค๋ฅผ ์บ์‹œํ•ด์„œ ์‚ฌ์šฉํ•ด๋„ ๋˜๋Š”์ง€?

GET, POST, PUT, PATCH, DELETE 5๊ฐœ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ 3๊ฐœ์˜ ์†์„ฑ๊ฐ’์ด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

Safe

POST, PUT, PATCH, DELETE ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์ง€๋งŒ GET์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์กฐํšŒ๋งŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ „ํ•˜๋‹ค

Idempotent

  • GET: 1๋ฒˆ ์กฐํšŒํ•˜๋‚˜ n๋ฒˆ ์กฐํšŒํ•˜๋‚˜ ๊ฒฐ๊ณผ๊ฐ’์ด ๋™์ผํ•˜๋‹ค
  • PUT: 1๋ฒˆ ๋Œ€์ฒดํ•œ ์ดํ›„๋ถ€ํ„ฐ ์ดํ›„์— ๋™์ผํ•œ ์š”์ฒญ์„ ๊ณ„์†ํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ’์€ ๋™์ผํ•˜๋‹ค
  • DELETE: 1๋ฒˆ ์‚ญ์ œ ์ดํ›„๋ถ€ํ„ฐ N๋ฒˆ ์š”์ฒญํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ’์€ ์—ฌ์ „ํžˆ ์‚ญ์ œ๋œ ์ƒํƒœ๋กœ ๋™์ผ
  • POST: ๊ฒฐ์ œ ์š”์ฒญ์„ ๊ฐ€์ •ํ•˜๋ฉด 1๋ฒˆ ์š”์ฒญ๊ณผ n๋ฒˆ ์š”์ฒญ์˜ ๊ฒฐ๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค (์ค‘๋ณต ๊ฒฐ์ œ ๋ฐœ์ƒ)

๋ฉฑ๋“ฑ์„ฑ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๊ฐ€ ์ •์ƒ ์‘๋‹ต์„ ์ฃผ์ง€ ๋ชปํ–ˆ์„๋•Œ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋™์ผํ•œ ์š”์ฒญ์„ ์ž๋™์œผ๋กœ ํ•ด๋„ ๋˜๋Š”์ง€ (n๋ฒˆ)์— ๋Œ€ํ•œ ๊ธฐ์ค€์ด ๋œ๋‹ค.

Cacheable

GET, HEAD, POST, PATCH 4๊ฐ€์ง€๊ฐ€ ์ด๋ก ์ƒ ์บ์‹ฑ ๊ฐ€๋Šฅํ•˜๋‹ค ํ•˜์ง€๋งŒ POST, PATCH๋Š” ๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ๊นŒ์ง€ ์บ์‹œ ํ‚ค๋กœ ๊ณ ๋ คํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ GET, HEAD 2๊ฐœ๋งŒ ์บ์‹ฑ์— ์ด์šฉํ•˜๊ณ  ์žˆ๋‹ค.

ECDSA - 2

Signature ์ƒ์„ฑ

๋น„๋Œ€์นญํ‚ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”-๋ณตํ˜ธํ™”, ์„œ๋ช… ์ƒ์„ฑ ๋ฐ ๊ฒ€์ฆ ๋‘ ๊ฐ€์ง€๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค

์ง€๋‚œ๋ฒˆ ๋Œ€์นญํ‚ค์™€ ๋น„๋Œ€์นญํ‚ค์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๋ฉด์„œ ์„œ๋ช… ์ƒ์„ฑ ๋ฐ ๊ฒ€์ฆ์— ๋Œ€ํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ–ˆ๋Š”๋ฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋” ์ž์„ธํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์ž

  • ์„œ๋ช…ํ•˜๋ ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ•ด์‹œํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด ํŠน์ • ๊ธธ์ด์˜ ๋ฐ์ดํ„ฐ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค
  • Private Key๋ฅผ ํ†ตํ•ด์„œ ํ•ด์‹œ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์•”ํ˜ธํ™” ํ•œ๋‹ค

์ง€๋‚œ๋ฒˆ์—๋„ ์„ค๋ช…ํ–ˆ์—ˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ Public Key๋ฅผ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”, Private Key๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜์ง€๋งŒ ์„œ๋ช… ์ƒ์„ฑ ๋ฐ ๊ฒ€์ฆ๊ณผ์ •์—์„œ๋Š” ๋ฐ˜๋Œ€๋‹ค.

  // MARK: - Signature Base64
	/// Representation์€ ํ˜„์žฌ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ ํƒ
	/// ์–ด๋–ค ํƒ€์ž…์˜ String์„ ์ƒ์„ฑํ• ์ง€๋Š” ์ƒํ™ฉ์— ๋งž๊ฒŒ base64 or Hex String
  func makeSignatureBase64(
    plainString: String
  ) -> String? {
    if let data = plainString.data(using: .utf8),
       let sig = try? privateKey.signature(for: SHA256.hash(data: data)) {
      return sig.Representation.base64EncodedString()
    } else {
      return nil
    }
  }

์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์„œ๋ช…ํ•˜๋ ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๋’ค ์„œ๋ช…์„ ๋งŒ๋“ค์–ด ๋‚ด๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

(Swift์—์„œ Hash ํ•จ์ˆ˜๋Š” 256, 384, 512 ์„ธ ๊ฐ€์ง€๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๋”ฐ๋กœ 256์ด ๋””ํดํŠธ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค)

ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹ ๊ฒฝ์จ์ค„ ๋ถ€๋ถ„์€ ์„œ๋ช…์„ Validation ํ•˜๋Š” ๊ณณ์—์„œ

  • ๋ช‡ bit ์งœ๋ฆฌ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๊ฐ€?
  • ์„œ๋ช…๋œ ๋ฐ์ดํ„ฐ๋ฅผ base64 String, hexString์ค‘ ์–ด๋–ค ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๊ฐ€?

์ •๋„๋ฅผ ์‹ ๊ฒฝ์จ์ฃผ๋ฉด ๋œ๋‹ค.


Signature ๊ฒ€์ฆ

์„œ๋ช…์„ ๊ฒ€์ฆ ํ•˜๋Š” ๊ณผ์ • ์ž์ฒด๋Š”

  • Private Key๋ฅผ ํ†ตํ•ด ์•”ํ˜ธํ™”๋œ ์„œ๋ช…์„ Public Key๋ฅผ ํ†ตํ•ด ๋ณตํ˜ธํ™” ๋˜๋Š”์ง€?
  • ๋ณตํ˜ธํ™” ๋œ ์„œ๋ช…์ด ์›๋ณธ๊ณผ ๋™์ผํ•œ์ง€?

๋‘ ๊ฐ€์ง€๋กœ ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•˜๊ณ  ์‹ฌ์ง€์–ด P256.PublicKey์— ๋ฉ”์„œ๋“œ๋กœ ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

์šฐ๋ฆฌ์—๊ฒŒ ๋ฌธ์ œ๋Š”

  • ์„œ๋ช…์„ ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ Public Key
  • ์„œ๋ช… ๋‚ด์šฉ
  • ์•”ํ˜ธํ™” ๋œ ์„œ๋ช…

์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ›์•„์˜จ ์œ„์˜ ์„ธ ๊ฐ€์ง€๋ฅผ Swift์˜ P256.PublicKey, P256.Signing.ECDSASignature ํƒ€์ž…์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜ํ•ด์•ผ ํ•˜๋Š”๊ฐ€?์ด๋‹ค. ์ด๋Š” ์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฅผ๊ฒƒ ๊ฐ™์€๋ฐ ์„œ๋ฒ„์—์„œ ๋ณด๋‚ด๋Š” ์ฃผ๋Š” ํƒ€์ž…์„ Data ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝ์‹œํ‚ค๊ณ  ์ด๋ฅผ ์ด์šฉํ•ด PublicKey, Signing.ECDSASignature ํƒ€์ž…์œผ๋กœ ์ดˆ๊ธฐํ™” ํ•˜๋ฉด ๋œ๋‹ค.

func validate(
    publicKey: String,
    plainString: String,
    sig: String
  ) -> Bool {
  // sigType: String to P256.Signing.ECDSASignature Type
  // pubType: String to P256.Signing.PublicKey Type
  let digest = SHA256.hash(data: plainData)
  P256.Signing.PublicKey.isValidSignature(sigType, for: digest)
}

ECDSA๋ฅผ ํ†ตํ•œ ํ‚ค ์ƒ์„ฑ, ์„œ๋ช… ์ƒ์„ฑ ๋ฐ ๊ฒ€์ฆ์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋Š”๋ฐ ์‚ฌ์‹ค ์ •๋ฆฌํ•˜๊ณ  ๋ณด๋ฉด ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•œ๋ฐ ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๋‚ด์šฉ์ด๋ผ ์‹œ๊ฐ„์ด ์ข€ ๊ฑธ๋ ธ๋‹ค.

์‚ฌ์‹ค ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ด์™ธ์— ๋น„๋Œ€์นญํ‚ค์˜ Private Key๋ฅผ iOS์—์„œ ์–ด๋””์— ์ €์žฅํ•  ๊ฒƒ์ธ๊ฐ€? ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ–ˆ์—ˆ๋Š”๋ฐ ํ‚ค์ฒด์ธ ๋งŒํ•œ ๊ณณ์ด ์—†๋Š”๊ฒƒ ๊ฐ™๋‹ค. ํ‚ค ์ €์žฅ ๊ด€๋ จ์— ๋Œ€ํ•ด์„œ๋Š” ์šฐ์„  ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ชจ๋‘ ์ •๋ฆฌํ•˜๊ณ  ๋‚œ ์ดํ›„์— ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.

์ด์ œ ๋‹ค์Œ์—๋Š” RSA๋ฅผ ํ†ตํ•œ ์•”ํ˜ธํ™”-๋ณตํ˜ธํ™”๊ณผ์ •์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๊ณ , AES๋ฅผ ํ†ตํ•œ ์•”ํ˜ธํ™”-๋ณตํ˜ธํ™”๋ฅผ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.

๋ ˆํผ๋Ÿฐ์Šค

์• ํ”Œ ๊ณต์‹๋ฌธ์„œ - 1
์• ํ”Œ ๊ณต์‹๋ฌธ์„œ - 2

RSA - 2

2) Encrypt

์ผ๋ฐ˜์ ์œผ๋กœ ๋น„๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ๋Š” ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด์„œ ์•”ํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ๋น„๋ฐ€ํ‚ค๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

(์„œ๋ช…๊ณผ ๊ฒ€์ฆ๊ณผ์ •์—์„œ๋Š” ๋น„๋ฐ€ํ‚ค๋ฅผ ํ†ตํ•ด์„œ ์„œ๋ช…๊ณผ์ •์„ ์•”ํ˜ธํ™” ์‹œ์ผœ์„œ ๋ณด๋‚ด๊ณ  ๊ณต๊ฐœํ‚ค๋ฅผ ํ†ตํ•ด์„œ ๋ณตํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค)

โ†’ ์ด์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋Œ€์นญํ‚ค์™€ ๋น„๋Œ€์นญํ‚ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•œ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค.

/// RSA - Encrypt plain string to rsa base64 String
  func encryptByRSA(
    plainString: String
  ) -> String? {
    var error: Unmanaged<CFError>?
    let algorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA256

    guard
      let publicKey = self.publicKey,
      SecKeyIsAlgorithmSupported(publicKey, .encrypt, algorithm),
      let plainData = plainString.data(using: .utf8),
      let ciperData = SecKeyCreateEncryptedData(
        publicKey,
        algorithm,
        plainData as CFData,
        &error
      )
    else { return nil }

    return cfDataTobase64String(ciperData)
  }

Public Key๋ฅผ ํ†ตํ•ด์„œ ํ‰๋ฌธ์„ ์•”ํ˜ธํ™” ํ•˜๋Š” ๊ตฌํ˜„ ์ž์ฒด๋Š” ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ๋„ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  Security์—์„œ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํ•˜๋‹ค. ํ•˜์ง€๋งŒ ECDSA์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ตฌํ˜„ ์ž์ฒด๋ณด๋‹ค๋Š” ์„œ๋ฒ„ ํ˜น์€ ์ด๋ฏธ ๊ตฌํ˜„๋œ ๊ณณ๊ณผ ์ŠคํŽ™์„ ๋งž์ถ”๋Š” ๊ณผ์ •์ด ์ค‘์š”ํ•˜๋‹ค.

RSA ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•œ ์•”ํ˜ธํ™” ๋ณตํ˜ธํ™” ๊ณผ์ •์—์„œ๋Š” ํŒจ๋”ฉ์˜ต์…˜์„ ์„ค์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋ฅผ ๋‹ค๋ฅธ ๊ณณ๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ •ํ•ด์•ผ ์„œ๋กœ ์ •์ƒ์ ์ธ encrypt, decrypt๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฝ”๋“œ์—์„œ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋“ฏ์ด SecKeyAlgorithm ์„ค์ •์„ ํ†ตํ•ด์„œ ๋‹ค์–‘ํ•œ ํŒจ๋”ฉ, ํ•ด์‹œํ•จ์ˆ˜ ์˜ต์…˜๋“ค์ด ์žˆ๋Š”๋ฐ ์ด ์ค‘์—์„œ ๋‹ค๋ฅธ ๊ณณ๊ณผ ๋™์ผํ•œ ์˜ต์…˜์„ ์ฐพ์•„์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

(GPT ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ–ˆ์„ ๋•Œ SecPadding ์„ ํ†ตํ•ด์„œ ํŒจ๋”ฉ์˜ต์…˜์„ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ๋“ค์ด ๋งŽ์•˜๋Š”๋ฐ ์•„์‰ฝ๊ฒŒ๋„ iOS15 ์ดํ›„์— deprecated ๋˜์—ˆ๋‹ค)

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด encrypt ํ•˜๋ ค๋Š” ํ‰๋ฌธ์„ ๋ฐ์ดํ„ฐ๋กœ ๋งŒ๋“ค๊ณ  public key๋ฅผ ์ด์šฉํ•ด์„œ ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ์˜ต์…˜์„ ํ†ตํ•ด์„œ encrypt๋ฅผ ์ˆ˜ํ–‰ํ•œ ๊ฒฐ๊ณผ๊ฐ€ CFData type์œผ๋กœ ciperData์— ๋‹ด๊ธฐ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•  ๋•Œ Data Type๋ณด๋‹ค๋Š” Hex String, Base64String ํƒ€์ž…์œผ๋กœ ๋ณด๋‚ด์ค€๋‹ค.

private func cfDataTobase64String(
    _ cfData: CFData
  ) -> String? {
    let data = cfData as Data
    let base64String = data.base64EncodedString()
    return base64String
  }

3) Decrypt

/// RSA - Decrypt rsa base64 String to plain String
  func decryptByRSA(
    encodedString: String
  ) -> String? {
    var error: Unmanaged<CFError>?
    let algorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA256

    guard
      let privateKey = self.privateKey,
      SecKeyIsAlgorithmSupported(privateKey, .decrypt, algorithm),
      let encodedData = base64StringToCFData(encodedString),
      let ciperData = SecKeyCreateDecryptedData(
        privateKey,
        algorithm,
        encodedData,
        &error
      )
    else { return nil }

    return cfDataToString(ciperData)
  }

๋ณตํ˜ธํ™” ํ•˜๋Š” ์ฝ”๋“œ๋Š” ์•”ํ˜ธํ™”๋œ String์„ CFData๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  private key๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์  ์ด์™ธ์—๋Š” encrypt๊ณผ ๋ณ„๋ฐ˜ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

private func cfDataToString(
    _ cfData: CFData
  ) -> String? {
    let length = CFDataGetLength(cfData)
    if let bytes = CFDataGetBytePtr(cfData) {
      let data = Data(bytes: bytes, count: length)
      return String(data: data, encoding: .utf8)
    } else {
      return nil
    }
  }

decrypt ๊ฒฐ๊ณผ๋กœ๋Š” base64 Stringํƒ€์ž…์ด ์•„๋‹Œ String ํ‰๋ฌธ์ด ๋‚˜์˜ค๋„๋ก ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.


RSA๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

  • ์„œ๋ฒ„์—์„œ RSA Public Key๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ
  • ์„œ๋ฒ„์— RSA Public Key๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ

ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ํ˜•ํƒœ๊ฐ€ ์กด์žฌํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ „์ž์˜ ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋Š” request body๋ฅผ ์•”ํ˜ธํ™” ์‹œํ‚ค๋Š” ๋กœ์ง, ํ›„์ž๋Š” ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์•”ํ˜ธํ™” ๋œ response body๋ฅผ ๋ณตํ˜ธํ™” ์‹œํ‚ค๋Š” ๋กœ์ง์ด ํ•„์š”ํ•˜๋‹ค.

์ „์ž์˜ ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ public key๋ฅผ SecKey ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์ด ์ถ”๊ฐ€์ ์œผ๋กœ ๊ตฌํ˜„๋˜์–ด์•ผ ํ•œ๋‹ค. ์„œ๋ฒ„์—์„œ ์–ด๋–ค ํ˜•์‹์œผ๋กœ public key๊ฐ€ ์˜ฌ์ง€๋Š” ์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ ์ด ๊ณผ์ •์—์„œ representation์„ ์„ค์ •ํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ ๋•Œ๋ฌธ์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ ํƒ์„ ๊ฒฐ์ •ํ–ˆ๋‹ค.

private func stringToSecKey(
    _ privateKey: String
  ) -> SecKey? {
    let keyAttributes: [CFString: Any] = [
      kSecAttrKeyType: kSecAttrKeyTypeRSA,
      kSecAttrKeyClass: kSecAttrKeyClassPublic,
      kSecAttrKeySizeInBits: 2048
    ]
    var error: Unmanaged<CFError>?
    if let privateKeyData = Data(base64Encoded: privateKey),
       let secKey = SecKeyCreateWithData(
        privateKeyData as CFData,
        keyAttributes as CFDictionary,
        &error
       ) {
      return secKey
    } else {
      return nil
    }
  }

๋งŒ์•ฝ raw Representation์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์œ„์˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ SecKey๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 8

HTTP ํ—ค๋” - ์บ์‹œ

์บ์‹œ

  • ์บ์‹œ๋Š” ๋ฐ์ดํ„ฐ๋‚˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜์—ฌ ๋ฐ˜๋ณต์ ์ธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • ๋ฐ์ดํ„ฐ๋‚˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋ณต์‚ฌํ•ด ๋†“๋Š” ์ž„์‹œ ์žฅ์†Œ

์ฒ˜์Œ์— ์บ์‹ฑ์„ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ์บ์‹ฑํ•  ์ •๋ณด๋ฅผ ์บ์‹œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฐ๋‹ค๊ณ ๋งŒ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์บ์‹œ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ด๋Ÿฐ ์—ญํ• ์„ ํ•˜๋Š” ๋ฌผ๋ฆฌ์  ์žฅ์น˜๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด๊ณ  ์บ์‹ฑ ์ž์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ(๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ)๋‚˜ ๋””์Šคํฌ(๋””์Šคํฌ ์บ์‹œ) ์–ด๋””์—์„œ๋“  ํ•  ์ˆ˜ ์žˆ๋‹ค.

HTTP ํ†ต์‹ ์—์„œ ์บ์‹œ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ํ™•์ธํ•ด๋ณด์ž
Untitled

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ์šฉ๋Ÿ‰์ด ํฐ ์ด๋ฏธ์ง€๋ฅผ ์š”์ฒญํ–ˆ๋‹ค. 1๋ถ„ํ›„์— ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋™์ผํ•œ ์ด๋ฏธ์ง€๋ฅผ ์š”์ฒญํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์„œ๋ฒ„๋Š” ๋‹ค์‹œ ๋™์ผํ•œ ์ด๋ฏธ์ง€๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ต๊ฐ’์œผ๋กœ ์ค€๋‹ค.

  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์—๋„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์šด๋ฐ›์•„์•ผ ํ•œ๋‹ค
  • ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•œ๋‹ค
  • ๋Š๋ฆฐ ์œ ์ € ๊ฒฝํ—˜(์นด์นด์˜คํ†ก ํ”„๋กœํ•„์„ ๋ˆŒ๋Ÿฌ ํ”„๋กœํ•„ ํ™”๋ฉด์ด ๋‚˜์˜ฌ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์šด ๋ฐ›์œผ๋ฉด ?)

์บ์‹œ๋ฅผ ํ†ตํ•ด์„œ ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
Untitled 1

Untitled 2

์ฒ˜์Œ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ต์„ ์ค„ ๋•Œ ์บ์‹œ ์œ ํšจ ์‹œ๊ฐ„์„ ์ฃผ๋ฉด ํ•ด๋‹น ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์—†์ด ์บ์‹œ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ ํšจ์‹œ๊ฐ„์ด ๋๋‚œ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์ด๋ฏธ์ง€๋ฅผ ์š”์ฒญํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ์„ฑ๋Šฅ์„ ๋” ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์„๊นŒ? ์บ์‹œ ์œ ํšจ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋์ง€๋งŒ ์„œ๋ฒ„์—์„œ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์‹œ ๋‹ค์šด ๋ฐ›์„ ํ•„์š”๊ฐ€ ์—†์ง€ ์•Š์„๊นŒ?

โ†’ ์กฐ๊ฑด๋ถ€ ์š”์ฒญ์„ ํ†ตํ•ด์„œ ํ•ด๊ฒฐ


๊ฒ€์ฆ ํ—ค๋”์™€ ์กฐ๊ฑด๋ถ€ ์š”์ฒญ

์บ์‹œ ์œ ํšจ์‹œ๊ฐ„์ด ๋๋‚˜์„œ ์„œ๋ฒ„์— ๋‹ค์‹œ ์š”์ฒญ์„ ํ•˜๋ฉด

  • ์„œ๋ฒ„์—์„œ ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•จ โ‡’ ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ
  • ์„œ๋ฒ„์—์„œ ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ โ‡’ ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์šฐ๋ฆฌ๋Š” ํ›„์ž์˜ ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ์บ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ์ค„์ด๊ณ  ์‹ถ๋‹ค. ๊ทธ๋Ÿผ ์บ์‹œ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์™€ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

Untitled 3

์ฒ˜์Œ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์บ์‹œ ์œ ํšจ๊ธฐ๊ฐ„๊ณผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ„ ๊ฐ’์„ ํ•จ๊ป˜ ์ค€๋‹ค.

Untitled 4

์ด์ œ ์บ์‹œ ์œ ํšจ์‹œ๊ฐ„์ด ๋๋‚œ ์‹œ์ ์— ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์—๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ„์„ ํ—ค๋”์— ๋„ฃ์–ด์„œ ๊ฐ™์ด ์š”์ฒญํ•œ๋‹ค.

Untitled 5

๊ทธ๋Ÿผ ์„œ๋ฒ„์—์„œ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์˜ ๋ณ€๊ฒฝ ์‹œ์ ๊ณผ ์ด๋ฅผ ๋น„๊ตํ•ด์„œ ๋ฆฌ์†Œ์Šค์˜ ๋ณ€๊ฒฝ์ด ์žˆ์—ˆ๋‹ค๋ฉด ๋‹ค์‹œ ์‘๋‹ต์œผ๋กœ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ  ๋ณ€๊ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” 304 ์ƒํƒœ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์‚ฌ์šฉ ํ•ด๋„ ๋จ์„ ์•Œ๋ ค์ฃผ๊ณ  ์บ์‹œ ์œ ํšจ๊ธฐ๊ฐ„์„ ๊ฐฑ์‹ ์‹œ์ผœ์ค€๋‹ค.

์ด๋•Œ ๋ฌผ๋ก  ์š”์ฒญ-์‘๋‹ต ๊ณผ์ •์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์ด ์—†๋Š”๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ HTTP ๋ฉ”์‹œ์ง€์— ๊ธฐ์กด์— ๋‹ค์šด ๋ฐ›๋˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์šฉ๋Ÿ‰์ด ๋งค์šฐ ์ž‘์•„์ง„๋‹ค.


์œ„์˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์œ ๋ฌด๋ฅผ ํŒŒ์•…ํ•˜๋Š”๋ฐ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ ์ˆ˜์ •๋œ ์‹œ๊ฐ„๋งŒ ๋ฐ”๋€ ๊ฒฝ์šฐ์—๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๋‹ค์šด๋ฐ›๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋˜๋Š” ์‹ค์ œ๋กœ ์ฃผ์„๊ฐ™์€ ์ •๋ณด๋งŒ ๋ฐ”๋€Œ๊ณ  ํฌ๊ฒŒ ์˜ํ–ฅ์ด ์—†๋Š” ๋ณ€๊ฒฝ๋งŒ ์žˆ๋˜ ๊ฒฝ์šฐ๋„ ๊ธฐ์กด ์บ์‹œ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌํ™œ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ์ ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ Last-Modified๊ฐ€ ์•„๋‹Œ ETag๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Entity-Tag๋Š” ๋ฐ์ดํ„ฐ์— ๋งค์นญ ๋˜๋Š” ์ด๋ฆ„์œผ๋กœ ํŒŒ์ผ์„ ๊ธฐ์ค€์œผ๋กœ ํ•ด์‹œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. (๋ฌผ๋ก  ์ž„์˜์˜๋กœ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Œ)

Untitled 6 Untitled 7

์ด์ œ ์บ์‹œ ์œ ํšจ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋œ ๊ฒฝ์šฐ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ„ ๊ธฐ์ค€์ด ์•„๋‹Œ ETag๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์บ์‹œ ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋™์ผํ•œ์ง€๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.


๊ฒ€์ฆํ—ค๋”์™€ ์กฐ๊ฑด๋ถ€ ์š”์ฒญ

  • ์„œ๋ฒ„ โ†’ ํด๋ผ์ด์–ธํŠธ (๊ฒ€์ฆํ—ค๋”)
    • ์บ์‹œ ๋ฐ์ดํ„ฐ์™€ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ™์€์ง€ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ์ดํ„ฐ
    • ETag, Last-Modified
  • ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„ (์กฐ๊ฑด๋ถ€ ์š”์ฒญ)
    • ํ˜„์žฌ ์บ์‹œ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌํ™œ์šฉ ํ•ด๋„ ๋˜๋Š”์ง€์— ๋”ฐ๋ฅธ ๋ถ„๊ธฐ
    • If-Modified-Since: Last-Modified
    • If-None-Match: ETag

์บ์‹œ ์ œ์–ด ํ—ค๋”

Cache-Control

  • Cache-Control: max-age
    • ์บ์‹œ ์œ ํšจ ์‹œ๊ฐ„, ์ดˆ ๋‹จ์œ„๊ฐ’
  • Cache-Control: no-cache
    • ๋ฐ์ดํ„ฐ๋Š” ์บ์‹œํ•ด๋„ ๋˜์ง€๋งŒ, ํ•ญ์ƒ ์›Œ์„œ๋ฒ„์— ๊ฒ€์ฆ
  • Cache-Control: no-store
    • ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์บ์‹œํ•˜๋ฉด ์•ˆ๋จ
  • Cache-Control: must-revalidate
    • ์บ์‹œ ์œ ํšจ์‹œ๊ฐ„ ๋งŒ๋ฃŒํ›„ ์ตœ์ดˆ ์กฐํšŒ์‹œ ์›์„œ๋ฒ„์— ๊ฒ€์ฆ
    • ์›์„œ๋ฒ„ ์ ‘๊ทผ ์‹คํŒจ์‹œ 504 (no-cache์™€์˜ ์ฐจ์ด์ )
  • Cache-Control: public
    • ์‘๋‹ต์ด public ์บ์‹œ์— ์ €์žฅ๋˜๋„ ๋จ
  • Cache-Control: private
    • ์‘๋‹ต์ด ์‚ฌ์šฉ์ž๋งŒ์„ ์œ„ํ•œ๊ฐ’์œผ๋กœ private(๊ธฐ๋ณธ๊ฐ’)

Pragma

HTTP 1.0 ํ•˜์œ„ ํ˜ธํ™˜์„ ์œ„ํ•ด์„œ ์‚ฌ์šฉ

// ํ™•์‹คํ•œ ์บ์‹œ ๋ฌดํšจํ™”
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache

Expires

์บ์‹œ ๋งŒ๋ฃŒ์ผ ์ง€์ •(๋‚ ์งœ), ์œ ์—ฐํ•œ Cache-Control: max-age(์ดˆ๋‹จ์œ„) ์‚ฌ์šฉ๊ถŒ์žฅ, ๋‘˜์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด Expires๋ฌด์‹œ

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 2

URI์™€ ์›น ๋ธŒ๋ผ์šฐ์ € ์š”์ฒญ ํ๋ฆ„

URI(Uniform Resource Identifier)

ํšŒ์‚ฌ์—์„œ ์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” URI์™€ URL์— ๋Œ€ํ•œ ์ฐจ์ด์ ์„ ํ™•์ธํ•ด๋ณด์ž

Untitled

  • URI๋Š” ๋‹จ์–ด ์˜๋ฏธ ๊ทธ๋Œ€๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์‹๋ณ„ํ•˜๋Š” Identifier๋ฅผ ์˜๋ฏธ
  • URL, URN์€ URI๋ผ๋Š” ํฐ ๋ฒ”์œ„์•ˆ์— ํฌํ•จ๋œ๋‹ค

URL(=Locater)

  • ํŠน์ • ์„œ๋ฒ„์˜ ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ง€์ •
  • ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ณด๋Š” http://naver.com ์ด๋Ÿฐ๊ฒƒ๋“ค์„ ์˜๋ฏธํ•œ๋‹ค

URN(=Name)

  • ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ด๋ฆ„์„ ์˜๋ฏธ
  • ์œ„์น˜๋Š” ๋ณ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋ฆ„์€ ๋ณ€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์†Œ์Šค ์œ„์น˜๊ฐ€ ๋ณ€ํ•˜๋”๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค
  • ํ•˜์ง€๋งŒ ์‹ค์ œ ์ด๋ฆ„๋งŒ์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋ณดํŽธํ™” ๋˜์ง€ ์•Š์•˜๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค

  • URI(๋ฆฌ์†Œ์Šค ์‹๋ณ„)์€ ํฌ๊ฒŒ URL, URN์œผ๋กœ ๋‚˜๋ˆ ์ง„๋‹ค
  • URN์€ ๋ณดํŽธํ™” ๋˜์ง€ ์•Š์•„์„œ ์ผ๋ฐ˜์ ์œผ๋กœ URL์„ ์‚ฌ์šฉํ•œ๋‹ค
  • ์—„๋ฐ€ํ•˜๊ฒŒ ๋ณด๋ฉด URL โ†’ URI (o), URI โ†’ URL (x) ํ˜•ํƒœ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ URI ~= URL ์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋œ๋‹ค. (ํ•ด๋‹น ๊ฐ•์˜์—์„œ๋Š” URI = URL๋กœ ์˜๋ฏธํ•œ๋‹ค)

URL

Untitled 1

  • Scheme: ์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœํ† ์ฝœ์„ ์ž‘์„ฑํ•œ๋‹ค ex) http, https, ftp
  • Userinfo: URL์— ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํฌํ•จํ•ด์„œ ์ธ์ฆํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค (๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)
  • Host: IP ์ฃผ์†Œํ˜น์€ ์ง€๋‚œ ์‹œ๊ฐ„์— ๋ฐฐ์šด DNS๋ฅผ ์ด์šฉํ•œ ๋„๋ฉ”์ธ๋ช…์„ ์ ๋Š”๋‹ค.
  • Port: ์ง€๋‚œ ์‹œ๊ฐ„์— ๋ฐฐ์šด Port๋ฅผ ์˜๋ฏธ http = 80, https = 443๋ฅผ ์‚ฌ์šฉ (์ผ๋ฐ˜์ ์œผ๋กœ ์ƒ๋žต)
  • Path: ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ๋ฅผ ์˜๋ฏธ
  • Query
    • key-value ํ˜•ํƒœ๋กœ ์กด์žฌ
    • ?๋กœ ์‹œ์ž‘ํ•˜๊ณ  &๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ
    • query parm, query string ์ด๋ผ๊ณ ๋„ ๋ถ€๋ฆ„ (value๊ฐ’์ด ์ „๋ถ€ string์œผ๋กœ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ)
    • ๊ฒฝํ—˜์ƒ GET์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ–ˆ์—ˆ์Œ
  • Fragment
    • html ๋‚ด๋ถ€ ๋ถ๋งˆํฌ (๋งํฌ ๋“ค์–ด๊ฐ€๋ฉด ํŠน์ •์œ„์น˜๋กœ ๊ฐ€๋˜๊ฒƒ๋“ค)
    • ์„œ๋ฒ„์— ์ „์†ก๋˜๋Š” ๊ฐ’์ด ์•„๋‹˜

Equatable

Equatable

์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค๋ณด๋ฉด Equatable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์„ ๋งŽ์ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์‚ฌ์‹ค ํ•ด๋‹น ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด

== , != ๊ณผ ๊ฐ™์€ ๋™๋“ฑ์„ฑ์„ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค ์ •๋„๋กœ๋งŒ ์•Œ๊ณ  ์žˆ๋Š”๋ฐ ์กฐ๊ธˆ๋งŒ ๋” ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค.

let a: Int = 1
let b: Int = 2
if a == b {
  print("True")
}

์œ„์™€ ๊ฐ™์ด a == b ๊ฐ€ ๊ฐ€๋Šฅํ–ˆ๋˜๊ฑด Int(Struct)๊ฐ€ Equatable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

protocol Equatable {
  static func == (lhs: Self, rhs: Self) -> Bool
}

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํด๋ž˜์Šค๋‚˜ ๊ตฌ์กฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋™์ผํ•œ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Eqautable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

import Foundation

class A: Equatable {

  var num: Int

  init(num: Int) {
    self.num = num
  }

  static func == (lhs: A, rhs: A) -> Bool {
    return lhs.num == rhs.num
  }
}

let a = A(num: 10)
let b = A(num: 10)
if a == b {
  print("equal") // equal
}

Equatable ํ”„๋กœํ† ์ฝœ์„ ๋“ค์—ฌ๋‹ค๋ณด๋ฉด statuc func == (lhs: Self, rhs: Self) โ†’ Bool ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ํด๋ž˜์ŠคA์— Equatable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ํด๋ž˜์Šค A์˜ ํ”„๋กœํผํ‹ฐ์ธ num์ด ๋™์ผํ•œ์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŒ๋ณ„ํ•ด์„œ Bool ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž

์ด๋•Œ lhs.num == rhs.num์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š” Int ํƒ€์ž…์ด Equatable ํ”„๋กœํ† ์ฝœ์„ ์ด๋ฏธ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

๊ทธ๋Ÿผ A๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ๋™๋“ฑ๋น„๊ต๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜๋‹ค๋ณด๋‹ˆ ์ฐธ์กฐํƒ€์ž…๊ณผ ๊ฐ’ํƒ€์ž…์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ์ •๋ฆฌ๊ฐ€ ํ•œ๋ฒˆ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค!

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 1

IP(=Internet Protocol)

  • ์ง€์ •ํ•œ ์ฃผ์†Œ์— ํŒจํ‚ท๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

Untitled

IP ํ”„๋กœํ† ์ฝœ๋งŒ์„ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์†ก,์ˆ˜์‹  ํ•˜๋Š” ๊ณผ์ •์€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ๋ฌผ๊ฑด์„ ์ฃผ๋ฌธํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์ฃผ์†Œ๊ฐ’์„ ์ž…๋ ฅํ•ด ๋ฌผ๊ฑด์„ ์ฃผ๋ฌธํ•˜๋ฉด ์„œ๋ฒ„์—์„œ ํ•ด๋‹น ์ฃผ๋ฌธ์„ ๋ฐ›๊ณ  ์‚ฌ์šฉ์ž์˜ ์ฃผ์†Œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ์ž๋ฃŒ๋ฅผ ๋ณด๋‚ด์ฃผ๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ IP ํ”„๋กœํ† ์ฝœ์—๋Š” ๋ช…ํ™•ํ•œ ํ•œ๊ณ„๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

1) ๋น„์—ฐ๊ฒฐ์„ฑ

ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„, ์„œ๋ฒ„ โ†’ ํด๋ผ์ด์–ธํŠธ ํ˜•ํƒœ๋กœ ํŒจํ‚ท์„ ๋ณด๋‚ผ ๋•Œ, ๋Œ€์ƒ ์„œ๋ฒ„๊ฐ€ ํŒจํ‚ท์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, IP ํ”„๋กœํ† ์ฝœ์„ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ํ†ต์‹ ์€ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š๊ณ  ์ผ๋ฐฉ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ํŒจํ‚ท์„ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค

2) ๋น„์‹ ๋ขฐ์„ฑ

ํ˜„์žฌ ๊ทธ๋ฆผ์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์‚ฌ์ด์— ๋‹จ์ˆœํžˆ ํ•˜๋‚˜์˜ ๋ฐ•์Šค๋กœ ํ‘œํ˜„๋˜์–ด ์žˆ์ง€๋งŒ ์‹ค์ œ ์ธํ„ฐ๋„ท์—์„œ๋Š” ์ˆ˜๋งŽ์€ ๋…ธ๋“œ๋ฅผ ๊ฑฐ์ณ์„œ ํŒจํ‚ท์ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค

  • ํŒจํ‚ท ์œ ์‹ค

์ˆ˜ ๋งŽ์€ ๋…ธ๋“œ๋ฅผ ๊ฑฐ์น˜๋ฉด์„œ ์„œ๋ฒ„๋กœ ๋ณด๋‚ธ ํŒจํ‚ท์ด ์œ ์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์šฐ๋ฆฌ๊ฐ€ ์ฃผ๋ฌธํ•œ ๋ฌผ๊ฑด์ด ๊ณค์ง€์•” ๋ฒ„๋ฎค๋‹ค ๋ฌผ๋ฅ˜์„ผํ„ฐ์—์„œ ๊ธธ์„ ์žƒ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ) ํ•˜์ง€๋งŒ ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์–ด๋–ค ํŒจํ‚ท์„ ๋ณด๋ƒˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ „ํ˜€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ๋ณด๋‚ธ ํŒจํ‚ท์ด ์œ ์‹ค๋˜์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค ์กฐ์ฐจ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ํŒจํ‚ท ์ „๋‹ฌ ์ˆœ์„œ

์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ, ํ•œ ๋ฒˆ์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ธฐ ๋ณด๋‹ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž˜๋ผ์„œ ๋ณด๋‚ด๊ฒŒ ๋˜๊ณ , ๊ทธ๋Ÿผ ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„ ๋กœ ํ†ตํ•˜๋Š” ๋…ธ๋“œ๋Š” ํ•˜๋‚˜๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ๋จผ์ € ๋ณด๋‚ธ ๋ฐ์ดํ„ฐ๋ณด๋‹ค ์ดํ›„์— ๋ณด๋‚ธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋จผ์ € ๋„์ฐฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์„œ๋ฒ„๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ฌ๊ฑฐ๋ผ๋Š” ์‚ฌ์‹ค์กฐ์ฐจ ๋ชจ๋ฅด๊ธฐ ๋–„๋ฌธ์— ์ด๋Ÿฐ ์ƒํ™ฉ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค


TCP(=Transmission Control Protocol)

์•ž์„œ ์‚ดํŽด๋ณธ IP์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ํƒ„์ƒํ•œ๊ฒŒ TCP์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์•ž์„  ๋ฌธ์ œ๋“ค์„ TCP๋ฅผ ์ด์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

![๋ชจ๋“  ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 1๊ฐ• ๊ฐ•์˜์ž๋ฃŒ]
Untitled 1

์ธํ„ฐ๋„ท ํ”„๋กœํ† ์ฝœ 4๊ณ„์ธต์„ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

์šฐ์„ , ์•ž์„œ ์‚ดํŽด๋ณธ Internet Protocol์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ TCP๊ฐ€ ์ถ”๊ฐ€๋œ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ IP ํŒจํ‚ท์„ TCP๋ผ๋Š” ์ƒ์ž๋กœ ํฌ์žฅํ•ด์„œ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

1) ์—ฐ๊ฒฐ์ง€ํ–ฅ

IP์—์„œ์˜ ๋น„์—ฐ๊ฒฐ์„ฑ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์ž…๋‹ˆ๋‹ค.

TCP๋Š” ์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์ „์— ๋จผ์ € ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€๋ฅผ ๋จผ์ € ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ์‹œ์ž‘ ์‹œ์ : 3 way handshak
์—ฐ๊ฒฐ์ข…๋ฃŒ ์‹œ์ : 4 way handshake (#23, ๊ด€๋ จ ์ด์Šˆ)

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ„ ์—ฐ๊ฒฐ์ด ์ •์ƒ์ ์ด์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2) ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ณด์žฅ

IP์—์„œ์˜ ํŒจํ‚ท ์œ ์‹ค์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์ด ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์–ด๋–ค ์ •๋ณด๋ฅผ ๋ณด๋‚ด๊ณ  ์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ํŒจํ‚ท์„ ๋ฐ›์œผ๋ฉด ํด๋ผ์ด์–ธํŠธ๋กœ ํŒจํ‚ท์„ ๋ฐ›์•˜๋‹ค๋Š” ack ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

๋งŒ์•ฝ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŒจํ‚ท์„ ๋ณด๋‚ด๊ณ  ์ผ์ •์‹œ๊ฐ„ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ack์„ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋‹ค์‹œ ํŒจํ‚ท์„ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3) ํŒจํ‚ท ์ „๋‹ฌ ์ˆœ์„œ

IP์—์„œ์˜ ํŒจํ‚ท ์ „๋‹ฌ ์ˆœ์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์ž…๋‹ˆ๋‹ค.

TCP๋ฅผ ํ†ตํ•ด ํŒจํ‚ท์˜ ์ˆœ์„œ๋ฅผ ๋ฏธ๋ฆฌ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ฌ๋ฐ”๋ฅธ ์ˆœ์„œ๋กœ ํŒจํ‚ท์ด ์˜ค์ง€ ์•Š์€ ๊ฒฝ์šฐ, ๋‹ค์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋‚ด๋ถ€์ ์œผ๋กœ ์กฐํ•ฉํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


UDP(=User Datagram Protocol)

  • ์—ฐ๊ฒฐ์„ฑ์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค โ†’ ์‹ ๋ขฐ์„ฑ x
  • ๋‹จ์ˆœํ•˜๊ณ  ๋น ๋ฅด๋‹ค
  • IP + Port

PORT

Untitled 2

ํด๋ผ์ด์–ธํŠธ์—์„œ ์—ฌ๋Ÿฌ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ฐ™์€ IP์— ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•  ๊ฒƒ์ธ๊ฐ€?

ํŒจํ‚ท์— ์กด์žฌํ•˜๋Š” port๋ฅผ ํ†ตํ•ด์„œ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.


DNS(=Domain Name System)

์šฐ๋ฆฌ๊ฐ€ www.google.com์„ ์ž…๋ ฅํ•˜๋ฉด DNS ์„œ๋ฒ„์—์„œ IP์ฃผ์†Œ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋Š”๊ฒƒ ์ฒ˜๋Ÿผ IP ์ „ํ™”๋ฒˆํ˜ธ๋ถ€๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • IP๋Š” ๊ธฐ์–ตํ•˜๊ธฐ ์–ด๋ ค์›€
  • IP๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ

์ด๋Ÿฌํ•œ ํŠน์ง• ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ IP์ฃผ์†Œ ๋ณด๋‹ค๋Š” DNS์„œ๋ฒ„์— IP๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๋„๋ฉ”์ธ ์ด๋ฆ„์„ ํ†ตํ•ด์„œ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค.

[SwiftUI] TabBar Hidden

TabBar Hidden

SwiftUI๋ฅผ ์ด์šฉํ•ด์„œ TabBar๋ฅผ Hidden ์‹œํ‚ค๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ–ˆ๋˜ ๋ฒ„๊ทธ๋ฅผ ๊ณต์œ ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

SwiftUI 3.0 ๊ธฐ์ค€์œผ๋กœ TabBar Hidden์„ SwiftUI ์ž์ฒด์ ์œผ๋กœ ์ง€์›ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค

(SwiftUI 4.0์€ ์ง€์›ํ•ด์ค€๋‹ค. ์• ํ”Œ๋†ˆ๋“ค์•„..)

import SwiftUI
import UIKit

struct TabBarAccessor: UIViewControllerRepresentable {
  var callback: (UITabBar) -> Void
  private let proxyController = ProxyViewController()

  func makeUIViewController(context: UIViewControllerRepresentableContext<TabBarAccessor>) -> UIViewController {
    proxyController.callback = callback
    return proxyController
  }

  func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TabBarAccessor>) {
  }

  // ํƒญ๋ฐ”๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ํ—ฌํผ ๋ทฐ์ปจ
  private class ProxyViewController: UIViewController {
    var callback: (UITabBar) -> Void = { _ in }

    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)

      if let tabBarController = self.tabBarController {
        callback(tabBarController.tabBar)
      }
    }
  }
}

extension View {
  func setTabBarVisibility(isHidden: Bool) -> some View {
    background(TabBarAccessor(callback: { tabBar in
      tabBar.isHidden = isHidden
      tabBar.layoutIfNeeded()
    }))
  }
}

SwiftUI์—์„œ ์ž์ฒด์ ์œผ๋กœ ์ง€์›ํ•ด์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— UIViewController๋ฅผ ๋ž˜ํ•‘์‹œ์ผœ์„œ UIKit ๊ธฐ๋ฐ˜์œผ๋กœ ViewWillAppear ์‹œ์ ์— ํ•ด๋‹น ๋ทฐ์ปจ์—์„œ tabBar๋ฅผ ์ฐพ์•„์„œ ํด๋กœ์ €ํ˜•ํƒœ๋กœ ๋„˜๊ฒจ์ฃผ๋„๋ก ๊ตฌ์„ฑํ•˜๊ณ  ViewModifier๋ฅผ ํ†ตํ•ด ํ•ด๋‹น tabBar๋ฅผ hidden ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ฐพ์•„์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ TabBar๊ฐ€ ์กด์žฌํ•˜๋Š” RootView์—์„œ push ๋˜๋Š” ๊ฒฝ์šฐ, ์ƒˆ๋กญ๊ฒŒ ๋‚˜ํƒ€๋‚  ํ™”๋ฉด์—์„œ TabBar๋ฅผ hidden ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

Simulator Screen Recording - iPhone 14 Pro - 2023-01-21 at 14 10 04

์ •์ƒ์ ์œผ๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ๋ณด์˜€์ง€๋งŒ ์œ„์˜ ๋ฒ„๊ทธ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ ์•ผ ๋ง์•˜๋‹คโ€ฆ

push ๋œ ํ™”๋ฉด์˜ ์ตœํ•˜๋‹จ์— View๋ฅผ ๊ทธ๋ฆฌ๋ฉด TabBar๋Š” ๋ณด์ด์ง€ ์•Š์ง€๋งŒ ๊ธฐ์กด์˜ TabBar๋งŒํผ์˜ ๋†’์ด๋ฅผ ๋จน๊ณ  ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‹ฌ์ง€์–ด ์ด ์ƒํƒœ์—์„œ background, inActive โ†’ active ์ƒํƒœ๋กœ ์ „ํ™˜์ด ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ๋†’์ด๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.


background, inActive โ†’ active ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋  ๋•Œ, SwiftUI View์—์„œ ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ง€๋Š” ์•Š์•˜์ง€๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์•ผ๋งค(?)๋กœ ํ•ด๊ฒฐ๋ฒ•์„ ์ฐพ์•„ ์ •๋ฆฌํ•ด๋†“๊ณ ์ž ํ•œ๋‹ค.

Simulator Screen Recording - iPhone 14 Pro - 2023-01-29 at 21 48 36

์˜์ƒ์„ ํ†ตํ•ด์„œ ์–ด๋–ค ๋ฐฉ๋ฒ•์„ ์ด์šฉํ–ˆ๋Š”์ง€ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ์„๊ฒƒ ๊ฐ™์€๋ฐ ํ•ด๊ฒฐ๋ฒ•์€ bottom์˜ safeArea๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ์ด๋‹ค!

(์‹ฌ์ง€์–ด ์œ„ ์˜์ƒ์—๋Š” ๋‚˜์™€์žˆ์ง€ ์•Š์ง€๋งŒ Bottom SafeArea๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ์น˜๊ฐ€ ์—†๋Š” ๋ชจ๋ธ์—์„œ๋„ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ ๋™์ผํ•˜๊ฒŒ ํ•ด๊ฒฐ๊ฐ€๋Šฅํ•˜๋‹ค)

  • SafeArea๋ฅผ ๋ฌด์‹œํ•˜๋ฉด ์ด์ „๊ณผ ๊ฐ™์ด active ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ, TabBar์˜์—ญ์˜ ๋†’์ด๊ฐ€ ์‚ฌ๋ผ์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.
  • ์•ฑ์ด ์ผœ์ง€๋Š” ์‹œ์ ์— SafeArea Bottom Height๋ฅผ EnvironmentValue๋กœ ์ €์žฅ์‹œํ‚จ๋‹ค.
  • ์ €์žฅํ•œ SafeArea Bottom Height ๋งŒํผ padding์„ ์ถ”๊ฐ€์ ์œผ๋กœ ์ค€๋‹ค
  • TabBar๊ฐ€ Hidden๋˜๋Š” View์—์„œ ๊ธฐ์กด์˜ TabBar Hidden์— ignoreSafeArea(.bottom)์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์€ ViewModifier๋Š” ์ˆœ์„œ์— ์˜ํ–ฅ์„ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์—

safeArea Bottom height ๋งŒํผ padding์„ ์ฃผ๊ณ  ๋‚œ ์ดํ›„์— Tabbar๋ฅผ hidden ์‹œํ‚ค๋ฉด์„œ safeArea๋ฅผ ๋ฌด์‹œํ•ด์•ผ ํ•œ๋‹ค!

import SwiftUI

extension UIApplication {
  var keyWindow: UIWindow? {
    connectedScenes
      .compactMap {
        $0 as? UIWindowScene
      }
      .flatMap {
        $0.windows
      }
      .first {
        $0.isKeyWindow
      }
  }
}

private extension UIEdgeInsets {
  var swiftUiInsets: EdgeInsets {
    EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right)
  }
}

private struct SafeAreaBottomKey: EnvironmentKey {
  static var defaultValue: CGFloat {
    UIApplication.shared.keyWindow?.safeAreaInsets.swiftUiInsets.bottom ?? 0.0
  }
}

extension EnvironmentValues {
  var safeAreaBottom: CGFloat {
    self[SafeAreaBottomKey.self]
  }
}
struct FriendDetailView: View {
  @Environment(\.safeAreaBottom)
  var safeAreaBottom

  var body: some View {
    VStack {
      Text("์—๋Ÿฌ ์ผ€์ด์Šค")
        .font(.title2)

      Spacer()

      Button(
        action: { },
        label: {
          Text("๋ฒ„ํŠผ์˜ ์œ„์น˜๊ฐ€?")
            .font(.body)
        }
      )
    }
    .padding(.bottom, safeAreaBottom)
    .setTabBarVisibility(isHidden: true)
  }
}

Simulator Screen Recording - iPhone 14 Pro - 2023-01-29 at 22 25 48

์ •์ƒ๋™์ž‘ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
์ „์ฒด์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์ฑ…๋ณด๋‹ค๋Š” ์•ผ๋งค๋กœ ์–ด๋–ป๊ฒŒ๋“  ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜๋Š”๋ฐ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์•„์‹œ๋Š” ๋ถ„์€ [email protected]์œผ๋กœ ์—ฐ๋ฝ ์ฃผ์‹œ๋ฉด
์ •๋ง ๋„ˆ๋ฌด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 3

HTTP

TCP/IP ์™€ HTTP

์ง€๋‚œ ์‹œ๊ฐ„๊นŒ์ง€ TCP/IP, UDP์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ์ „์†ก ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ–ˆ๋Š”๋ฐ HTTP์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๊ธฐ ์ด์ „์— ๋‘˜์˜ ์ฐจ์ด๋ฅผ ๋ช…ํ™•ํžˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ณ ์ž ํ•œ๋‹ค.

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด HTTP๋Š” TCP/IP ๋ณด๋‹ค ์ƒ์œ„ ๊ฐœ๋…์ด๋‹ค.

Untitled
  • ์‘์šฉ๊ณ„์ธต
    • HTTP, FTP, SMTP๋“ฑ ๋„คํŠธ์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ
  • ์ „์†ก๊ณ„์ธต
    • TCP, UDP๋“ฑ ์‹œ์Šคํ…œ์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†ก
  • ์ธํ„ฐ๋„ท๊ณ„์ธต
    • IP ๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ๋ฅผ ๋ผ์šฐํŒ…
  • ๋ฌผ๋ฆฌ๊ณ„์ธต
    • ํ•˜๋“œ์›จ์–ด ๋„คํŠธ์›Œํฌ

TCP/IP 4๊ณ„์ธต ๊ด€์ ์—์„œ ๋ฐ”๋ผ๋ณด๋ฉด HTTP๋Š” ์‘์šฉ๊ณ„์ธต์— ์†ํ•˜๊ณ  TCP,UDP๋Š” ์ „์†ก๊ณ„์ธต, IP๋Š” ์ธํ„ฐ๋„ท ๊ณ„์ธต์— ์†ํ•ด์žˆ๋Š”๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. HTTP ๊ณ„์ธต์—์„œ HTTP ๋ฉ”์‹œ์ง€๋ฅผ ์ž‘์„ฑ
  2. TCP ๊ณ„์ธต์—์„œ HTTP ๋ฉ”์‹œ์ง€๋ฅผ ํŒจํ‚ท์œผ๋กœ ๋ถ„ํ•ด
  3. IP๊ณ„์ธต์—์„œ ์ „์†ก์œ„์น˜๋ฅผ ํ™•์ธ
  4. ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•˜์—ฌ ์ „์†ก

HTTP์˜ ๊ธฐ๋ฐ˜ ํ”„๋กœํ† ์ฝœ์ด TCP๋ผ๋Š” ์˜๋ฏธ๋Š” ์œ„์™€ ๊ฐ™์ด HTTP ํ†ต์‹ ์˜ ์ผ๋ จ์˜ ๊ณผ์ •์— TCP๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ๋ผ๊ณ  ์ดํ•ดํ–ˆ๋‹ค. (๋ฌผ๋ก  UDP๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค)

โ†’ ํ•ด๋‹น ๋‚ด์šฉ ๊ด€๋ จํ•ด์„œ๋Š” ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ณ„์† ์ถ”๊ฐ€ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.


HTTP(=Hypter Text Transfer Protocol)

์ธํ„ฐ๋„ท์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ํ”„๋กœํ† ์ฝœ๋กœ ๊ฑฐ์˜ ๋ชจ๋“  ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๊ณ  Web์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„ HTTP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

HTTP ๋ฒ„์ „

  • HTTP 1.1 โ†’ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋ฒ„์ „์ด๊ณ  TCP๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ  ์žˆ์Œ
  • HTTP 2.0 โ†’ 1.1๋ฒ„์ „์—์„œ ์„ฑ๋Šฅ ๊ฐœ์„ 
  • HTTP 3.0 โ†’ TCP๊ฐ€ ์•„๋‹Œ UDP๋ฅผ ์ด์šฉํ•ด์„œ ์†๋„ ๊ฐœ์„ (hand shake ๊ณผ์ • x)

(๊ตฌ๊ธ€์—์„œ F12๋ฅผ ํ†ตํ•ด์„œ HTTP ๋ฒ„์ „์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ)

HTTP ํŠน์ง•

  • ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„ ๊ตฌ์กฐ
  • ๋ฌด์ƒํƒœ(=Stateless), ๋น„์—ฐ๊ฒฐ์„ฑ
  • HTTP ๋ฉ”์‹œ์ง€

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋ฉด ์œ„์˜ ๋‚ด์šฉ์ด๊ณ  HTTP์˜ ํŠน์ง•์— ๋Œ€ํ•ด์„œ ์ฐจ๋ก€๋Œ€๋กœ ํ•˜๋‚˜์”ฉ ์ •๋ฆฌํ•ด๋ณด์ž.


ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„ ๊ตฌ์กฐ

  • ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ๋Œ€๊ธฐ
  • ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ’์„ ์‘๋‹ต

์„œ๋ฒ„์—์„œ ์•ฑ์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ(์•ฑ)๋Š” ๊ฒฐ๊ณผ๊ฐ’์— ๋”ฐ๋ผ UI๋ฅผ ๊ทธ๋ ค์ค€๋‹ค.

ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๊ตฌ์กฐ๊ฐ€ ๊ณ ๋„ํ™” ๋˜๋ฉด ์œ„์™€ ๊ฐ™์ด ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ์—ญํ•  ๋ถ„๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ๋…๋ฆฝ์ ์œผ๋กœ ๋ฐœ์ „ํ•  ์ˆ˜ ์žˆ๋‹ค. (์‹ฌ์ง€์–ด ๋ชจ๋ฐ”์ผ์€ ์›น๊ณผ ๋‹ฌ๋ฆฌ ๊ตฌ๊ธ€์ด๋‚˜ ์• ํ”Œ์˜ ์‹ฌ์‚ฌ๊ณผ์ •๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ์‹ฌ์‚ฌ ์—†์ด ์„œ๋ฒ„ ์ˆ˜์ •๋งŒ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.)


๋ฌด์ƒํƒœ(=Stateless)

์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ๋ณด์กดํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•ด๋‹น ๋ฌธ์žฅ๋งŒ ๋ณด๊ณ  ์ดํ•ดํ•˜๊ธฐ๋Š” ์–ด๋ ค์šฐ๋‹ˆ๊นŒ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด์„œ ์ดํ•ดํ•ด๋ณด์ž.

Stateful

/// ์ ์›์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
๊ณ ๊ฐ: ๋…ธํŠธ๋ถ ์–ผ๋งˆ์—์š”?
์ ์›(A): 380๋งŒ์›์ด์š”

๊ณ ๊ฐ: 1๊ฐœ ์ฃผ์„ธ์š”
์ ์›(A): ์ผ์‹œ๋ถˆ์ธ๊ฐ€์š”? ํ• ๋ถ€์ธ๊ฐ€์š”?

๊ณ ๊ฐ: 36๊ฐœ์›” ๋ฌด์ด์ž ํ• ๋ถ€์š”
์ ์›(A): ๋„ค

์ ์›์ด ์ด์ „ ๊ณ ๊ฐ์˜ ์š”์ฒญ์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•œ ๋Œ€ํ™”์ด๋‹ค. ๋งŒ์•ฝ ์ ์›์ด ์ค‘๊ฐ„์ค‘๊ฐ„ ๋ฐ”๋€๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

/// ์ ์›์ด ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ
๊ณ ๊ฐ: ๋…ธํŠธ๋ถ ์–ผ๋งˆ์—์š”?
์ ์›(A): 380๋งŒ์›์ด์š”

๊ณ ๊ฐ: 1๊ฐœ ์ฃผ์„ธ์š”
์ ์›(B): ..์˜ˆ? ๋ญ˜ 1๊ฐœ ๊ตฌ๋งคํ•˜์‹œ๋Š” ๊ฑด๊ฐ€์š”?

๊ณ ๊ฐ: 36๊ฐœ์›” ๋ฌด์ด์ž ํ• ๋ถ€์š”
์ ์›(C): ...์˜ˆ? ๋ฌด์Šจ ์ œํ’ˆ ๋ช‡๊ฐœ๋ฅผ 36๊ฐœ์›” ํ• ๋ถ€๋กœ ๊ตฌ๋งคํ•˜์‹œ๋Š”๊ฑด๊ฐ€์š”?

์ ์›์ด ์ด์ „ ์ƒํƒœ๋“ค์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ •์ƒ์ ์ธ ๋Œ€ํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•˜๊ณ  ์ด์ „ ์ƒํƒœ์—๋“ค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ค์‹œ ๋ฌผ์–ด์•ผ ๊ณ ๊ฐ์˜ ์š”๊ตฌ๋ฅผ ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

Stateless

/// ์ ์›์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
๊ณ ๊ฐ: ๋…ธํŠธ๋ถ ์–ผ๋งˆ์—์š”?
์ ์›(A): 380๋งŒ์›์ด์š”

๊ณ ๊ฐ: ๋…ธํŠธ๋ถ 1๊ฐœ ์ฃผ์„ธ์š”
์ ์›(A): ์ผ์‹œ๋ถˆ์ธ๊ฐ€์š”? ํ• ๋ถ€์ธ๊ฐ€์š”?

๊ณ ๊ฐ: ๋…ธํŠธ๋ถ 1๊ฐœ 36๊ฐœ์›” ๋ฌด์ด์ž ํ• ๋ถ€์š”
์ ์›(A): ๋„ค
/// ์ ์›์ด ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ
๊ณ ๊ฐ: ๋…ธํŠธ๋ถ ์–ผ๋งˆ์—์š”?
์ ์›(A): 380๋งŒ์›์ด์š”

๊ณ ๊ฐ: ๋…ธํŠธ๋ถ 1๊ฐœ ์ฃผ์„ธ์š”
์ ์›(B): ์ผ์‹œ๋ถˆ์ธ๊ฐ€์š”? ํ• ๋ถ€์ธ๊ฐ€์š”?

๊ณ ๊ฐ: ๋…ธํŠธ๋ถ 1๊ฐœ 36๊ฐœ์›” ๋ฌด์ด์ž ํ• ๋ถ€์š”
์ ์›(C): ๋„ค

๋ฌด์ƒํƒœ์ธ ๊ฒฝ์šฐ์—๋Š” ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ์ ์›์œผ๋กœ ๋ฐ”๋€Œ๋”๋ผ๋„ ๊ณ ๊ฐ์ด ์ด์ „ ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๊ณผ ํ•จ๊ป˜ ์š”์ฒญํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ ๊ฐ์˜ ์š”๊ตฌ๋ฅผ ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ๊ณ ๊ฐ๊ณผ ์ ์›์ด ์•„๋‹Œ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๋กœ ์ƒ๊ฐํ•ด๋ณด์ž.

  • ์ค‘๊ฐ„์— ์ ์›์ด ๋ฐ”๋€Œ๋”๋ผ๋„ ๊ณ ๊ฐ์˜ ์š”๊ตฌ๋ฅผ ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์„œ๋ฒ„ ์ค‘ ์•„๋ฌด ์„œ๋ฒ„๋‚˜ ์‘๋‹ต๊ฐ’์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์ค‘๊ฐ„์— ์„œ๋ฒ„๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์ค‘๊ณ„์„œ๋ฒ„๋ฅผ ํ†ตํ•ด์„œ ๋‹ค๋ฅธ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์Šค์ผ€์ผ ์•„์›ƒ(=์ˆ˜ํ‰ ํ™•์žฅ)์ด ์‰ฌ์›Œ์ง„๋‹ค.

๋น„์—ฐ๊ฒฐ์„ฑ

HTTP๋Š” ์š”์ฒญ์„ ์ฃผ๊ณ  ๋ฐ›์„ ๋•Œ๋งŒ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๊ณ  ์‘๋‹ต์„ ์ฃผ๊ณ  ๋ฐ›์€ ์ดํ›„์—๋Š” ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง„๋‹ค.

  • ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์„ ๊ณ„์† ์œ ์ง€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • but, ์š”์ฒญ-์‘๋‹ต๋งˆ๋‹ค TCP/IP ์—ฐ๊ฒฐ์„ ์ƒˆ๋กœ ๋งบ์–ด์•ผ ํ•œ๋‹ค(handshake ๊ณผ์ • ํ•„์š”)
  • ์ด๋Ÿฐ ๋‚ญ๋น„๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ HTTP ์ง€์† ์—ฐ๊ฒฐ์„ ํ†ตํ•ด์„œ ๋ฌธ์ œ ํ•ด๊ฒฐ

HTTP ๋ฉ”์‹œ์ง€

Untitled 1 Untitled 2
  • ์‹œ์ž‘๋ผ์ธ
    • ์š”์ฒญ
      • method / request target / http version
    • ์‘๋‹ต
      • http version/ status code / reason - phrase
  • ํ—ค๋”
    • fieldname: field value
      • http ์ „์†ก์— ํ•„์š”ํ•œ ๋ถ€๊ฐ€ ์ •๋ณด๋“ค
  • ๋ฐ”๋””
    • ์‹ค์ œ๋กœ ์ „์†กํ•  ๋ฐ์ดํ„ฐ

ํ”„๋กœ์„ธ์Šค์™€ ์Šค๋ ˆ๋“œ

ํ”„๋กœ์„ธ์Šค์™€ ์Šค๋ ˆ๋“œ

์šฐ์„  ํ‚ค์›Œ๋“œ ์ค‘์‹ฌ์œผ๋กœ ๋จผ์ € ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ํ”„๋กœ๊ทธ๋žจ(Program) : ์–ด๋–ค ์ž‘์—…์„ ์œ„ํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ
  • ํ”„๋กœ์„ธ์Šค(Process) : ์šด์˜์ฒด์ œ๋กœ๋ถ€ํ„ฐ ์ž์›์„ ํ• ๋‹น๋ฐ›๋Š” ์ž‘์—…์˜ ๋‹จ์œ„
  • ์Šค๋ ˆ๋“œ(Thread) : ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ์‹คํ–‰๋˜๋Š” ์—ฌ๋Ÿฌ ํ๋ฆ„์˜ ๋‹จ์œ„

ํ”„๋กœ์„ธ์Šค๋Š” ๊ฐ๊ฐ์˜ ๋…๋ฆฝ๋œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ (Heap, Data, Stack, Code)๋ฅผ OS๋กœ ๋ถ€ํ„ฐ ํ• ๋‹น๋ฐ›๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ์„ธ์Šค๋‹น ์ตœ์†Œ 1๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ(๋ฉ”์ธ์Šค๋ ˆ๋“œ) ํ• ๋‹น ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ฐ ํ”„๋กœ์„ธ์Šค๋Š” ๋ณ„๋„์˜ ์ฃผ์†Œ๊ณต๊ฐ„์—์„œ ์‹คํ–‰๋˜๊ณ , ํ•œ ํ”„๋กœ์„ธ์Šค๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณ„๋„์˜ ํ†ต์‹ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ๋Š” ํ•œ ํ”„๋กœ์„ธ์Šค๋‚ด์—์„œ ์Šคํƒ ์˜์—ญ๋งŒ ๋”ฐ๋กœ ํ• ๋‹น๋ฐ›๊ณ  Code, Heap, Data ์˜์—ญ์„ ๊ณต์œ ๋ฐ›์•„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ• ๋‹น๋ฐ›์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์Šค๋ ˆ๋“œ๋Š” ํ•œ ํ”„๋กœ์„ธ์Šค ๋‚ด์— ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋“ค์€ ์„œ๋กœ ์ž์›์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.


๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค์™€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ

  • ๋ฉ€ํ‹ฐ-ํ”„๋กœ์„ธ์Šค : ํ•˜๋‚˜์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๋กœ ๊ตฌ์„ฑํ•ด์„œ ๊ฐ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ฒ˜๋ฆฌ

๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค์˜ ๊ฒฝ์šฐ ํ”„๋กœ์„ธ์Šค์˜ ํŠน์„ฑ์„ ์ƒ๊ฐํ•˜๋ฉด ์žฅ,๋‹จ์ ์„ ํŒŒ์•…ํ•˜๊ธฐ ์‰ฝ๋‹ค.

  • ํ”„๋กœ์„ธ์Šค๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์™€ ๋ณ„๋„์˜ ์ฃผ์†Œ๊ณต๊ฐ„์—์„œ ์‹คํ–‰๋œ๋‹ค -> ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค ์ค‘ ํ•˜๋‚˜์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋งŒ ์ฃฝ๊ณ  ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์—๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ํ•œ ํ”„๋กœ์„ธ์Šค์—์„œ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณ„๋„์˜ ํ†ต์‹ ์ด ํ•„์š”ํ•˜๋‹ค -> ํ”„๋กœ์„ธ์Šค๋ผ๋ฆฌ๋Š” ๋…๋ฆฝ๋œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ํ• ๋‹น ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— Context Switching์ด ๋ฐœ์ƒํ•˜๋ฉด ์บ์‰ฌ์— ์žˆ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์ง€์šฐ๊ณ  ์บ์‰ฌ์ •๋ณด๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์™€์•ผํ•œ๋‹ค.(์‹œ๊ฐ„์ ์„ ์†ํ•ด)

Context Switching : CPU์—์„œ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋Œ์•„๊ฐ€๋ฉด์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •, ๋™์ž‘์ค‘์ธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ๋‹ค์Œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์ž‘ํ•˜๋ฉด ์ด์ „์— ๋ณด๊ด€ํ–ˆ๋˜ ์ƒํƒœ๋ฅผ ๋ณต๊ตฌ


  • ๋ฉ€ํ‹ฐ-์Šค๋ ˆ๋“œ : ํ•˜๋‚˜์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๋กœ ๊ตฌ์„ฑํ•˜๊ณ  ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ฒ˜๋ฆฌ

๋งˆ์ฐจ๊ฐ€์ง€๋กœ ์Šค๋ ˆ๋“œ์˜ ํŠน์„ฑ์— ๋งž์ถฐ์„œ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž

  • ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค๋‚ด ์Šค๋ ˆ๋“œ๋“ค์€ ์ž์›์„ ๊ณต์œ ํ•œ๋‹ค -> ์Šค๋ ˆ๋“œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ๊ณผ์ •์ด ๊ฐ„๋‹จํ•˜๋ฏ€๋กœ ์‹œ์Šคํ…œ ์ž์› ์†Œ๋ชจ๊ฐ€ ์ค„์–ด๋“ ๋‹ค.
  • ์—ฌ๋Ÿญ๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์›์„ ํ• ๋‹นํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด ์ค„์–ด๋“ค์–ด ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ๋งŒ ๋ณด๋ฉด ๋ฉ€ํ‹ฐ-์Šค๋ ˆ๋“œ ๋ฐฉ์‹์ด ๋ฉ€ํ‹ฐ-ํ”„๋กœ์„ธ์Šค ๋ฐฉ์‹๋ณด๋‹ค ์ข‹์€์ ๋งŒ ์žˆ๋Š”๊ฒƒ ๊ฐ™์ง€๋งŒ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์ ๋“ค์ด ์กด์žฌํ•œ๋‹ค.

  • ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์˜ ๊ฒฝ์šฐ ์ž์›์„ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ์Šค๋ ˆ๋“œ๋ฅผ ์†Œ์œ ํ•œ ํ”„๋กœ์„ธ์Šค ์ „์ฒด๊ฐ€ ์˜ํ–ฅ ๋ฐ›๋Š”๋‹ค.

๋”ฐ๋ผ์„œ, ๋ฉ€ํ‹ฐ-์Šค๋ ˆ๋“œ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ฃผ์˜ ๊นŠ์€ ์„ค๊ณ„๊ฐ€ ํ•„์š”ํ•˜๋‹ค

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ - 02

Concurrency

1ํŽธ์— ์ด์–ด์„œ ๋‘๋ฒˆ์งธ ์ •๋ฆฌ๊ธ€์ด๋‹ค!

์‚ฌ์‹ค ๊ฐ•์˜๋ฅผ ๋น ๋ฅด๊ฒŒ ๋‹ค ๋“ฃ๊ณ  ์ •๋ฆฌํ•˜๋ฉด์„œ ๋ณต์Šตํ•˜๋Š” ๋Š๋‚Œ์œผ๋กœ ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ•์˜ ๋‚ด์šฉ์ด ์–ด๋ ค์›Œ์„œ ์ •๋ฆฌํ•˜๋ฉด์„œ ๋ณต์Šตํ•˜๊ณ  ๊ฐ•์˜ ๋‚ด์šฉ์„ ์ด์–ด์„œ ๋“ค์–ด์•ผ ํ• ๊ฒƒ ๊ฐ™๋‹ค ๐Ÿ˜‚

๋ณต์Šต

์˜ค๋Š˜์€ GCD์˜ ์ข…๋ฅ˜์™€ ํŠน์„ฑ, ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๊ทธ ์ „์— ์ด์ „์— ๋‹ค๋ค˜๋˜ ๋‚ด์šฉ์„ ํ•œ๋ฒˆ ์ •๋ฆฌ ํ•ด๋ณด์ž

  • ์ž‘์—…๋“ค์„ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์— ๋ถ„์‚ฐ ์‹œ์ผœ์„œ ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ด์šฉํ•œ๋‹ค
  • iOS์—์„œ๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  GCD/Operation Queue์— ๋„ฃ์–ด์ฃผ๋ฉด OS๊ฐ€ ์•Œ์•„์„œ ์“ฐ๋ ˆ๋“œ์— ์ผ์„ ๋ถ„๋ฐฐํ•œ๋‹ค
  • GCD/Operation Queue ์—๋Š” Serial queue, Concurrent queue ๋ผ๋Š” ํŠน์„ฑ์ด ์žˆ๋‹ค
  • ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ๋Š” ์–ด๋–ค ์ž‘์—…์„ ํ๋กœ ๋ณด๋‚ผ ๋•Œ ํ•ด๋‹น ์ž‘์—…์˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ๋ฐ”๋กœ ๋‹ค์Œ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค
  • ์ง๋ ฌ๊ณผ ๋™์‹œ๋Š” ํ์˜ ํŠน์„ฑ์œผ๋กœ ์ง๋ ฌ ํ์˜ ๊ฒฝ์šฐ ํ์— ํ• ๋‹น๋œ ์ž‘์—…์„ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๊ณ  ๋™์‹œํ๋Š” ํ์— ํ• ๋‹น๋œ ์ž‘์—…์„ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค

GCD์˜ ์ข…๋ฅ˜์™€ ํŠน์„ฑ

GCD(=Dispatch Queue) ๋Š” ํฌ๊ฒŒ 3๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฉ”์ธ ํ
  • ๊ธ€๋กœ๋ฒŒ ํ
  • ํ”„๋ผ์ด๋น— ํ(์ปค์Šคํ…€)

๋ฉ”์ธํ

๋ฉ”์ธ ํ๋Š” ์˜ค์ง ํ•œ ๊ฐœ๋งŒ ์กด์žฌํ•˜๊ณ , Serial ํŠน์„ฑ์„ ๊ฐ€์ง€๊ณ , ๋ฉ”์ธํ์— ํ• ๋‹น๋œ ์ž‘์—…๋“ค์€ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•œ๋‹ค!

์šฐ๋ฆฌ๊ฐ€ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ณ ๋ คํ•˜์ง€์•Š๊ณ  ๋‹จ์ˆœํžˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค๊ณ  ํ–ˆ์—ˆ๋‹ค. ๊ทธ๋Ÿผ ์šฐ๋ฆฌ๊ฐ€ ๋ณ„๋„์˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด ์ž‘์—…๋“ค์ด ๋ฉ”์ธ ํ์— ํ• ๋‹น๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

//DispatchQueue.main.sync {
  print("Hello")
//}

์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด ์šฐ๋ฆฌ๊ฐ€ ๋ณ„๋„์˜ ์ž‘์—…์„ ํ•˜์ง€ ์•Š์œผ๋ฉด DispatchQueue.main.sync๊ฐ€ ๊ฐ์‹ธ์ง„ ํ˜•ํƒœ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
(๋ฌผ๋ก  ์‹ค์ œ๋กœ ์ €๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ๊ฐ€ ์“ฐ๋ ˆ๋“œ-์„ธ์ดํ”„ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค!)

์ •๋ฆฌํ•ด๋ณด๋ฉด ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋„ ํ•˜๋‚˜ ๋ฉ”์ธํ๋„ ํ•˜๋‚˜ ์กด์žฌํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ๋ฉ”์ธํ๋Š” ํ•„์—ฐ์ ์œผ๋กœ Serialํ•œ ํŠน์„ฑ์„ ๊ฐ€์งˆ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ์™œ? ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์— ๋™์‹œ ์ž‘์—…์„ ๋„ฃ์„ ์ˆ˜๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ!!

๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ ์ด์•ผ๊ธฐ๊ฐ€ ๋‚˜์˜จ๊น€์— ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์˜ ์ค‘์š”ํ•œ ํŠน์„ฑ์— ๋Œ€ํ•ด์„œ ํ•˜๋‚˜ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ฉด UI ๊ด€๋ จ ์ž‘์—…์€ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•œ๋‹ค
์ด๋Š” iOS๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  OS์—์„œ ๋™์ผํ•˜๋‹ค. ์™œ ๊ทธ๋Ÿด๊นŒ? ๋งŒ์•ฝ ํ™”๋ฉด์ „ํ™˜ ๊ด€๋ จ ๋กœ์ง์ด ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋˜์–ด์„œ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๊ฒŒ ๋˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ ๋™์ž‘์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค!


๊ธ€๋กœ๋ฒŒ ํ

๊ธ€๋กœ๋ฒŒ ํ๋Š” Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง€๊ณ , QoS(=Quality of Service)๋ฅผ ํ†ตํ•ด์„œ ์ž‘์—…์˜ ์ค‘์š”๋„๋ฅผ ๊ฒฐ์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.

QoS์—๋Š” 6๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค.

  • userInteractive
  • userInitiated
  • default
  • utility
  • background
  • unspecified
let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)

์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€๊ฒƒ ๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ์ ์œผ๋ฉด ์œ„์™€ ๊ฐ™๋‹ค. ์šฐ๋ฆฌ๊ฐ€ QoS๋ฅผ ์„ค์ •๋งŒ ํ•ด์ฃผ๋ฉด ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ผ์— ๋” ๋งŽ์€ ์“ฐ๋ ˆ๋“œ๋ฅผ ์•Œ์•„์„œ ๋ฐฐ์น˜ ํ•ด์ค€๋‹ค.


ํ”„๋ผ์ด๋น— ํ(์ปค์Šคํ…€ ํ)

์ปค์Šคํ…€ ํ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” Serialํ•œ ํŠน์„ฑ์„ ๊ฐ€์ง€์ง€๋งŒ Concurrent ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ  QoS ๋˜ํ•œ ์„ค์ • ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

let customQueue = DispatchQueue(label: "bran")
let customConcurrentQueue = DispatchQueue(label: "bran", attributes: .concurrent)

์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด ์œ„์™€ ๊ฐ™๋‹ค. QoS๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด OS๊ฐ€ ์•Œ์•„์„œ ์ถ”๋ก ํ•ด์ค€๋‹ค!

โœ‹ ์ฃผ์˜์‚ฌํ•ญ

1) ๋ฉ”์ธ์“ฐ๋ ˆ๋“œ์—์„œ ๋‹ค๋ฅธ ํ๋กœ ์ž‘์—…์„ ๋ณด๋‚ผ ๋•Œ sync๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค

์•„๊นŒ ๋ฉ”์ธ ํ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•  ๋•Œ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ UI ๊ด€๋ จ๋œ ์ž‘์—…์ด ์ง„ํ–‰๋œ๋‹ค๊ณ  ํ–ˆ์—ˆ๋Š”๋ฐ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ์–ด๋–ค ์ž‘์—…์„ ํ์— sync ๋กœ ๋ณด๋‚ด๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 10 53 35

๋งŒ์•ฝ Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง€๋Š” ํ์— task1, task2 ๋ฅผ sync ํ•˜๊ฒŒ ๋ณด๋ƒˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 10 55 10

Concurrentํ•œ ํŠน์„ฑ์„ ๊ฐ€์ง€๋Š” ํ์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ syncํ•˜๊ฒŒ ๋ณด๋ƒˆ๊ธฐ ๋•Œ๋ฌธ์— UI๋ฅผ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ๋Š” ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋Š” ๋‹ค์Œ ํ์— ๋ณด๋‚ธ ์ž‘์—…๋“ค์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋‹ค์Œ ์ž‘์—…์„ ์ด์–ด์„œ ์ง„ํ–‰ํ•  ์ˆ˜ ์—†๋‹ค!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 10 59 11

ํ๋กœ ๋ณด๋‚ธ ์ž‘์—…๋“ค์ด ๋งŒ์•ฝ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด๋ผ๋ฉด ๊ทธ ์‹œ๊ฐ„๋™์•ˆ ์•ฑ์€ ๋ฉˆ์ถฐ๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๊ณ  ์งง๋”๋ผ๋„ ์šฐ๋ฆฌ๊ฐ€ ํ”ผํ•˜๊ณ  ์‹ถ๋˜ ์•ฑ์ด ๋ฒ„๋ฒ…์ด๋Š” ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋œ๋‹ค! ๊ทธ๋ž˜์„œ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ํ์— ์ž‘์—…์„ ๋ณด๋‚ผ ๋•Œ๋Š” ํ•ญ์ƒ ๋น„๋™๊ธฐ๋ฅผ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค!

2) ํ˜„์žฌ์™€ ๊ฐ™์€ ํ์— sync๋กœ ์ž‘์—…์„ ๋ณด๋‚ด๋ฉด ์•ˆ๋œ๋‹ค

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 11 06 45

์šฐ์„  ์œ„์™€ ๊ฐ™์ด Task1 ์•ˆ์— Task2๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ์ž‘์—…์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ํ˜„์žฌ Task1์„ Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง€๋Š” ํ์— ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ธ ์ƒํƒœ์ด๋‹ค. ๊ทผ๋ฐ Task1์— ํฌํ•จ๋œ Task2๋ฅผ Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง€๋Š” ํ์— ๋™๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ด๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

DispatchQueue.global().async {
// Task 1
  DispatchQueue.global().sync {
  // Task2
  }
}

์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์ด๋Ÿฐ ์ƒํ™ฉ์ด๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 11 25 18

Task2๋ฅผ Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง„ Queue์— sync ๋ฐฉ์‹์œผ๋กœ ๋„ฃ์–ด์คฌ๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ๋ ˆ๋“œ1์€ ํ•ด๋‹น ์ž‘์—…์ด ์™„๋ฃŒ ๋  ๋•Œ๊นŒ์ง€ Block ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
Concurrent ํŠน์„ฑ์„ ๊ฐ€์ง„ ํ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ๋Š” ๋“ค์–ด์˜จ Task2๋ฅผ ์“ฐ๋ ˆ๋“œ1, ์“ฐ๋ ˆ๋“œ2, ์“ฐ๋ ˆ๋“œ3 ์–ด๋””๋“  ๋„ฃ์–ด ์ค„ ์ˆ˜ ์žˆ๊ณ  ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์— ๊ฐœ์ž…ํ•  ์ˆ˜๋Š” ์—†๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์“ฐ๋ ˆ๋“œ1์—์„œ Task2๊ฐ€ ํ• ๋‹น๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-06-21 แ„‹แ…ฉแ„’แ…ฎ 11 34 35

Task2๊ฐ€ ์™„๋ฃŒ๋˜๊ธฐ ์ „์—๋Š” Task1์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š”๋ฐ Task2๊ฐ€ ๋ฉˆ์ถฐ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ์— ํ• ๋‹น๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์™„๋ฃŒ๋  ์ˆ˜๊ฐ€ ์—†๋‹ค.
์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ๊ต์ฐฉ์ƒํƒœ(๋ฐ๋“œ๋ฝ)์ด๋ผ๊ณ  ํ•œ๋‹ค!

๋ฌผ๋ก  ํ์—์„œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋กœ Task2๋ฅผ ํ• ๋‹นํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ ๊ทธ๋Ÿด ๊ฐ€๋Šฅ์„ฑ์ด ์กด์žฌํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜„์žฌ์™€ ๊ฐ™์€ ํ์— sync ๋กœ ์ž‘์—…์„ ๋ณด๋‚ด๋ฉด ์•ˆ๋œ๋‹ค!

๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์„๊นŒ?
global ํ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, QoS๋‹ค๋ฅธ ํ๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒน์น˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค!

์œ„์™€ ๋™์ผํ•œ ์ด์œ ๋กœ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ DispatchQueue.main.sync ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ดํ•ด ๋˜๊ฒ ์ฃ ?

  • ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ์—์„œ ๋ฉ”์ธ ํ๋กœ ์ž‘์—…์„ ๋ณด๋‚ธ๋‹ค ๋™๊ธฐ์ ์œผ๋กœ
  • ๋ฉ”์ธ ํ๋Š” ๋‹ค์‹œ ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋กœ ์ž‘์—…์„ ๋ณด๋‚ธ๋‹ค
  • ํ•˜์ง€๋งŒ ๋™๊ธฐ์ ์œผ๋กœ ๋ฉ”์ธ ํ์— ์ž‘์—…์„ ๋ณด๋ƒˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋Š” block ์ƒํƒœ์ด๋‹ค

ํ•ด๋‹น ๋‚ด์šฉ์€ ์•จ๋Ÿฐ๋‹˜์˜ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค!!

DispatchGroup ๊นŒ์ง€ ๊ฐ•์˜๋ฅผ ๋“ค์—ˆ๋Š”๋ฐ ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ๋ณต์Šตํ•˜๊ณ  ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

Hashable

Hashable

Hash์— ๋Œ€ํ•ด ๋จผ์ € ๊ฐ„๋žตํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™๋‹ค (๋ฐ”ํ‚น๋… ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฐ•์˜ ๋‚ด์šฉ)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ_2022-05-18_แ„‹แ…ฉแ„’แ…ฎ_11 27 07

๊ฒฐ๊ตญ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์–ด๋–ค key ๊ฐ’์„ Hash function์„ ํ†ตํ•ด์„œ ๊ณ ์ •๋œ ๊ธธ์˜ ๋ฐ์ดํ„ฐ๋กœ mapping ํ•ด์„œ Hash value๋ฅผ ์–ป์–ด๋‚ด๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์™œ ๊ตณ์ด Hash Value๋ฅผ ์–ป๋Š” ๊ณผ์ •์ด ํ•„์š”ํ• ๊นŒ? ๋ผ๋Š” ์˜๋ฌธ์ด ๋“ ๋‹ค๋ฉด ์œ„์˜ ์˜ˆ์‹œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ 16์ž๋ฆฌ์˜ ์นด๋“œ๋ฒˆํ˜ธ์„ ์ด์šฉํ•ด์„œ ํ•ด๋‹น ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์„ ์ฐพ๋Š” ๋ฌธ์ œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž!

๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ์ง€๋งŒ ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(1)์ด ๋˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋‹จ์ˆœํ•˜๊ฒŒ Counting Sort์™€ ์œ ์‚ฌํ•˜๊ฒŒ 0~9999 9999 9999 9999 ํฌ๊ธฐ์˜ String ํƒ€์ž… ๋ฐฐ์—ด์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์ธ๋ฑ์Šค์— ์นด๋“œ๋ฒˆํ˜ธ๋ฅผ ๋„ฃ์–ด์คŒ์œผ๋กœ์„œ O(1) ์˜ ๋ณต์žก๋„๋กœ ํ•ด๋‹น ์นด๋“œ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์˜ ๋ฐฉ๋ฒ•์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ต‰์žฅํžˆ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ์ด๋•Œ Hash์˜ ๊ฐœ๋…์„ ์ด์šฉํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ ˆ์•ฝํ•˜๋ฉด์„œ O(1)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์–‘ํ•œ Hash function์ด ์žˆ๊ฒ ์ง€๋งŒ ๋‹จ์ˆœํ•˜๊ฒŒ ์˜ˆ๋ฅผ ๋“ค๋ฉด ์นด๋“œ์˜ ์•ž์˜ 4์ž๋ฆฌ๋งŒ์„ ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ €์žฅํ•ด์„œ ๊ตฌ๋ถ„ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์ด๋ ‡๊ฒŒ ์ž„์˜์˜ ๊ธธ์ด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ ์ •๋œ ๊ธธ์ด์˜ ๋ฐ์ดํ„ฐ๋กœ mapping ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ Hash function์ด๋‹ค.

๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ์ค‘๋ณต๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ? ํ•˜๋Š” ์˜๋ฌธ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. Hash function์„ ์ด์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์˜ˆ์ƒํ–ˆ๋˜ ๊ฒƒ ์ฒ˜๋Ÿผ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•ด์„œ ์ถฉ๋™ ์ด ์ƒ๊ธฐ๊ฒŒ ๋˜๊ณ  ์ด๋Ÿฐ ์ถฉ๋Œ์ด ํ•„์—ฐ์ ์ด๋‹ค.

์ด๋Ÿฐ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‹ค์–‘ํ•œ ๊ธฐ๋ฒ•๋“ค์ด ์กด์žฌํ•œ๋‹ค. (Open Addressing, Chaning)


๊ทธ๋Ÿผ Hashable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์–ด๋–ค key ๊ฐ’์„ ํ•ด์‰ฌํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ hash value๋กœ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค key ๊ฐ’์„ ๊ณ ์œ ํ•œ hash value (Int)๋กœ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

protocol Hashable: Equatable {
  var hashValue: Int { get } // Deprecated
  func hash(into hasher: inout Hasher)
}

ํ”„๋กœํ† ์ฝœ์„ ์‚ดํŽด๋ณด๋ฉด ์•ž์„œ ๊ณต๋ถ€ํ•œ Equatable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๊ณ  hash ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Swift์˜ ๊ธฐ๋ณธ ์ž๋ฃŒํ˜•๋“ค์€ ์ด๋ฏธ Hashable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๋‹ค. (๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๊ฐ€ ๋”•์…”๋„ˆ๋ฆฌ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ๋•Œ key ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , Set์˜ ์ž๋ฃŒํ˜•์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค)

๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜•, ํด๋ž˜์Šค์™€ ๊ฐ™์ด ์šฐ๋ฆฌ๊ฐ€ ์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ Hashable์„ ์ฑ„ํƒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์ž

struct

// ๊ตฌ์กฐ์ฒด ๋‚ด์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ชจ๋‘ ๊ธฐ๋ณธ ์ž๋ฃŒํ˜•์ธ ๊ฒฝ์šฐ, Hashable ์ฑ„ํƒ๋งŒ์œผ๋กœ ๊ฐ€๋Šฅ
struct Human: Hashable {
  let name: String
  let height: Double
}

let a = Human(name: "bran", height: 27)
let b = Human(name: "bran", height: 27)
if a == b {
  print("์˜ค์ž‰ ๊ตฌ์กฐ์ฒด๋Š” ๊ฐ’ํƒ€์ž…์ด๋ผ Equable์„ ๋งŒ์กฑํ•˜๊ณ  ์žˆ๋Š”๊ฑด๊ฐ€?")
}

var dic: [Human : Int]

๊ตฌ์กฐ์ฒด์˜ ์ €์žฅํ”„๋กœํผํ‹ฐ๋Š” ๋ชจ๋‘ Hashable์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.

๊ตฌ์กฐ์ฒด๋Š” Swift 4.1 ์ดํ›„๋กœ Hashable์„ ์ฑ„ํƒ๋งŒํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

enum

// ์—ฐ๊ด€๊ฐ’์ด ์—†๋Š” ์—ด๊ฑฐํ˜•์€ Hashable์„ ์ฑ„ํƒํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ๊ตฌํ˜„
enum Gender {
  case male
  case female
}

var myDic: [Gender : Int]

enum GenderwithAge: Hashable {
  case male(age: Int)
  case female(man: Human)
}

์—ฐ๊ด€๊ฐ’์ด ์—†๋Š” ์—ด๊ฑฐํ˜•์˜ ๊ฒฝ์šฐ Hashable์„ ์ด๋ฏธ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๊ณ , ์—ฐ๊ด€๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์—ฐ๊ด€๊ฐ’์€ ๋ชจ๋‘ Hashable์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.

class

// ํด๋ž˜์Šค๊ฐ€ Hashableํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ 
class Man {
  let name: String = "Bran"
  let age: Int = 27
}

// Equatable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ 
extension Man: Equatable {
  static func == (lhs: Man, rhs: Man) -> Bool {
    return lhs.name == rhs.name && lhs.age == rhs.age
  }
}

// hash ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค
extension Man: Hashable {
  func hash(into hasher: inout Hasher) {
    hasher.combine(name)
    hasher.combine(age)
  }
}

ํด๋ž˜์Šค๋Š” Equatable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ณ  hash ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. hash ํ•จ์ˆ˜๋Š” Hasher์˜ combine์„ ์‚ฌ์šฉํ•ด์„œ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

(combine์—๋Š” ํ•ด๋‹น ํƒ€์ž…์˜ ๋ชจ๋“  ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ „๋‹ฌ, ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋Š” Hashable์„ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•จ)

HTTP ์›น ๊ธฐ๋ณธ ์ง€์‹ - 7

HTTP ํ—ค๋” - 1

  • field-name: field-value (๋„์›Œ์“ฐ๊ธฐ ํ—ˆ์šฉ)
  • HTTP ์ „์†ก์— ํ•„์š”ํ•œ ๋ชจ๋“  ๋ถ€๊ฐ€์ •๋ณด
  • ํ•„์š”์‹œ ์ž„์˜์˜ ํ—ค๋” ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
    • ์œ ์ € ๊ธฐ๊ธฐ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ—ค๋”์— ์‹ค์–ด์„œ ํ†ต์‹  ํ–ˆ๋˜ ๊ฒฝํ—˜

HTTP ํ—ค๋” ๋ถ„๋ฅ˜

RFC2616(๊ณผ๊ฑฐ)

  • General ํ—ค๋”: ๋ฉ”์‹œ์ง€ ์ „์ฒด์— ์ ์šฉ๋˜๋Š” ์ •๋ณด
  • Request ํ—ค๋”: ์š”์ฒญ ์ •๋ณด
  • Response ํ—ค๋”: ์‘๋‹ต ์ •๋ณด
  • Entity ํ—ค๋”: ์—”ํ‹ฐ๋”” ๋ฐ”๋”” ์ •๋ณด
HTTP/1.1 200 OK // ์‹œ์ž‘๋ผ์ธ
Content-Type: text/html;charset=UTF-8 // ์—”ํ‹ฐ๋”” ํ—ค๋”
Content-Length: 3423

<html> // ์—”ํ‹ฐ๋”” ๋ณธ๋ฌธ
...
</html>

HTTP ๋ฉ”์‹œ์ง€ ๊ตฌ์กฐ๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์‚ดํŽด๋ดค๋“ฏ์ด ์‹œ์ž‘๋ผ์ธ, ํ—ค๋”, ๊ณต๋ฐฑ, ๋ณธ๋ฌธ ๊ตฌ์กฐ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

์—”ํ‹ฐ๋”” ํ—ค๋”๋Š” ๋ฉ”์‹œ์ง€ ๋ณธ๋ฌธ์„ ํ†ตํ•ด ์ „๋‹ฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด์„ํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋“ค์„ ์ œ๊ณตํ•œ๋‹ค.

RFC723x

2014๋…„ ์ดํ›„๋กœ HTTP ํ‘œ์ค€์ด ๋ฐ”๋€Œ๋ฉด์„œ ์œ„์˜ ๊ตฌ์กฐ์—์„œ Entity๊ฐ€ Representation์œผ๋กœ ๋Œ€์ฒด๋˜๋Š” ํฐ ์ฐจ์ด์ ์ด ๋ฐœ์ƒํ–ˆ๋‹ค. (์™„์ „ํžˆ 1:1 ๋Œ€์‘๋˜๋Š” ๊ฐœ๋…์€ ์•„๋‹˜)

์‚ฌ์‹ค ๋‘˜์˜ ์ •ํ™•ํ•œ ์ฐจ์ด์ ์„ ํŒŒ์•…ํ•  ์ •๋„๋กœ ๊นŠ๊ฒŒ ๊ณต๋ถ€ํ•˜์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด

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

HTTP/1.1 200 OK // ์‹œ์ž‘๋ผ์ธ
Content-Type: text/html;charset=UTF-8 // ํ‘œํ˜„ ํ—ค๋”
Content-Length: 3423

<html> // ํ‘œํ˜„ ๋ฐ์ดํ„ฐ
...
</html>

ํ‘œํ˜„ํ—ค๋”

  • Content-Type: ํ‘œํ˜„ ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹

HTTP ๋ฉ”์„œ๋“œ ํ™œ์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ์ •๋ฆฌํ–ˆ๋˜ ๋ถ€๋ถ„์€ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ค์‹œ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž.

Content-Type์€ HTTP ์š”์ฒญ ๋˜๋Š” ์‘๋‹ต์˜ ๋ณธ๋ฌธ(content)์˜ ํ‘œํ˜„ ๋ฐ์ดํ„ฐ ํ˜•์‹์„ ์„ค๋ช…ํ•˜๊ณ  MIME ํƒ€์ž…์„ ์ด์šฉํ•ด ๋ฏธ๋””์–ด ํƒ€์ž…์„ ๋ช…์‹œํ•œ๋‹ค.

  • Content-Encoding: ํ‘œํ˜„ ๋ฐ์ดํ„ฐ ์ธ์ฝ”๋”ฉ

ํ‘œํ˜„ ๋ฐ์ดํ„ฐ๋ฅผ ์••์ถ•ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ

๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ์ชฝ์—์„œ ์ธ์ฝ”๋”ฉ ํ—ค๋”์˜ ์ •๋ณด๋ฅผ ์ด์šฉํ•ด์„œ ์••์ถ• ํ•ด์ œ [ex) gzip, deflate, identity]

  • Content-Language: ํ‘œํ˜„ ๋ฐ์ดํ„ฐ์˜ ์ž์—ฐ์–ธ์–ด

ํ‘œํ˜„ ๋ฐ์ดํ„ฐ์˜ ์ž์—ฐ์–ธ์–ด๋ฅผ ํ‘œํ˜„ [ex) ko, en, en-US]

  • Content-Length: ํ‘œํ˜„ ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด

๋ฐ”์ดํŠธ ๋‹จ์œ„, ์ „์†ก ์ฝ”๋”ฉ์„ ์‚ฌ์šฉํ•˜๋ฉด Cotent-Length๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋จ โ†’ ์กฐ๊ธˆ๋งŒ ๋‚ด๋ฆฌ์‹œ๋ฉด ํ•ด๋‹น ๋‚ด์šฉ ์ •๋ฆฌ


ํ˜‘์ƒ

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ ํ˜ธํ•˜๋Š” ํ‘œํ˜„ ์š”์ฒญ์ด๋ผ๋Š” ๋ฌธ์žฅ๋งŒ ๋ณด๋ฉด ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ํž˜๋“ค ์ˆ˜ ์žˆ๋Š”๋ฐ ์˜ˆ์ œ๋ฅผ ๋“ค์–ด์„œ ๊ฐ™์ด ์ดํ•ดํ•ด๋ณด์ž

Untitled Untitled 1

์œ„์˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋‹ค๊ตญ์–ด๋ฅผ ์ง€์›ํ•˜๋Š” ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ต์„ ์ค„ ๋•Œ ์š”์ฒญ์‹œ ํ˜‘์ƒ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ์œผ๋กœ ์ง€์›ํ•˜๋Š” ์˜์–ด๋กœ ์‘๋‹ต์„ ๋ฐ›๊ฒŒ๋œ๋‹ค.

ํ˜‘์ƒ๊ณผ ์šฐ์„ ์ˆœ์œ„

  • Quality Values๊ฐ€ ๋†’์„์ˆ˜๋ก ์šฐ์„ ์ˆœ์œ„
Untitled 2
  • ๊ตฌ์ฒด์ ์ผ์ˆ˜๋ก ์šฐ์„ ์ˆœ์œ„
Accept: text/*, text/plain, text/plain;format=flowed, **/*

1)* text/plain;format=flowed
2) text/plain
3) text/*
4) **/**
q๊ฐ’์„ ๋”ฐ๋กœ ๋ช…์‹œํ•˜์ง€ ์•Š์•„๋„ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์ด ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„๋‹ค.

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ๋ฐ›์„ ์‘๋‹ต ๊ฐ’์„ ๋•Œ ์„ ํ˜ธํ•˜๋Š” ํ˜•์‹์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์š”์ฒญ์‹œ์—๋งŒ ์‚ฌ์šฉ๋œ๋‹ค.


์ „์†ก๋ฐฉ์‹

  • ๋‹จ์ˆœ์ „์†ก
    • Content์— ๋Œ€ํ•œ ๊ธธ์ด๋ฅผ ์•Œ๊ณ  ์žˆ์„ ๋•Œ ์‚ฌ์šฉ ํ•œ๋ฒˆ์— ์š”์ฒญํ•˜๊ณ  ํ•œ๋ฒˆ์— ๋ฐ›์Œ
  • ์••์ถ•์ „์†ก
    • Content-Encoding์„ ํ†ตํ•ด์„œ ์–ด๋–ป๊ฒŒ ์••์ถ•๋˜์—ˆ๋Š”์ง€๋ฅผ ํ‘œํ˜„ํ•ด์•ผํ•œ๋‹ค.
  • ๋ถ„ํ• ์ „์†ก
    • Content-Length๋ฅผ ๋ณด๋‚ด๋ฉด ์•ˆ๋œ๋‹ค.
Untitled 3
  • ๋ฒ”์œ„์ „์†ก
    • ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•ด์„œ ์š”์ฒญ(์ด๋ฏธ์ง€ ๊ฐ™์ด ํฐ ํŒŒ์ผ์„ ๋ฐ›์„ ๋•Œ ์ค‘๊ฐ„๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ฐ›๋Š” ๊ฒฝ์šฐ ์ƒ๊ฐ)

์ผ๋ฐ˜์ •๋ณด

  • Form
    • ์œ ์ € ์—์ด์ „ํŠธ์˜ ์ด๋ฉ”์ผ ์ •๋ณด
  • Referer
    • ํ˜„์žฌ ์š”์ฒญ๋œ ํŽ˜์ด์ง€์˜ ์ด์ „ ์›จ ํŽ˜์ด์ง€ ์ฃผ์†Œ
    • ์œ ์ž… ๊ฒฝ๋กœ๋ฅผ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Œ
  • User-Agent
    • ํด๋ผ์ด์–ธํŠธ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ •๋ณด (์„œ๋ฒ„๋กœ๊ทธ์— Postman, Alamofire๊นŒ์ง€ ์ฐํžˆ๋˜๊ฑฐ ์ƒ๊ฐ)
    • ์–ด๋–ค ์ข…๋ฅ˜์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํŒŒ์•… ๊ฐ€๋Šฅ
  • Server
    • ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ORIGIN ์„œ๋ฒ„์˜ ์†Œํ”„ํŠธ์›จ์–ด ์ •๋ณด
  • Date
    • ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•œ ๋‚ ์งœ์™€ ์‹œ๊ฐ„

ํŠน๋ณ„ํ•œ ์ •๋ณด

  • Host
    • ์š”์ฒญํ•œ ํ˜ธ์ŠคํŠธ ์ •๋ณด
    • ํ•˜๋‚˜์˜ IP์ฃผ์†Œ์— ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ์ด ์ ์šฉ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•„์ˆ˜
    • ์š”์ฒญ์—์„œ ์‚ฌ์šฉ
  • Location
    • 30x ์‘๋‹ต ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด ๋ฆฌ๋‹ค์ต๋ ˆํŠธ ์‹œํ‚ค๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ
    • 201์—์„œ ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ ์œ„์น˜๋ฅผ ์•Œ๋ ค์ค„ ๋–„ ์‚ฌ์šฉ
  • Retry-After
    • ์œ ์ € ์—์ด์ „ํŠธ๊ฐ€ ๋‹ค์Œ ์š”์ฒญ์„ ํ•˜๊ธฐ์ „๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ์‹œ๊ฐ„
  • Authorization
    • ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์— ์ „๋‹ฌํ•  ๋•Œ ์‚ฌ์šฉ
    • 401์—์„œ ์œ ์ € ์ธ์ฆ ์‹คํŒจ์‹œ WWW-Authenticate๋กœ ์ธ์ฆ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ๋ ค์คŒ

์ฟ ํ‚ค

์ฟ ํ‚ค๋Š” ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด๋Š” ์ž‘์€ ๋ฐ์ดํ„ฐ ์กฐ๊ฐ

์ฟ ํ‚ค์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฟ ํ‚ค๋ฅผ ์™œ ์‚ฌ์šฉํ•˜๋Š”์ง€๋ฅผ ๋จผ์ € ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

HTTP ํŠน์„ฑ์„ ๋‹ค์‹œ ๋“ค์—ฌ๋‹ค ๋ณด๋ฉด

  • ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„ ๊ตฌ์กฐ
  • ๋ฌด์ƒํƒœ, ๋น„์—ฐ๊ฒฐ์„ฑ

๋ฌด์ƒํƒœ(Stateless), ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ๋Š” ์ด์ „ ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์„œ๋ฒ„์— ๋ณด๋‚ด์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ์ง€๋งŒ ์Šค์ผ€์ผ ์•„์›ƒ์ด ์‰ฌ์›Œ์ง„๋‹ค๊ณ  ์ •๋ฆฌํ•œ๋ฐ” ์žˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ „ ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์— ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋ฌด์—‡์ด ์žˆ์„๊นŒ?

๊ฐ„๋‹จํ•˜๊ฒŒ ๋ชจ๋“  ์š”์ฒญ์— ์ด์ „ ์ƒํƒœ ์ •๋ณด๋ฅผ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ์€ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ?

์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ๊ฒƒ์ด ์ฟ ํ‚ค์ด๋‹ค.

Untitled 4

๋จผ์ € ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ฟ ํ‚ค๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

Untitled 5

์ดํ›„ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ, ์ฟ ํ‚ค์— ์žˆ๋Š” ์ •๋ณด๋ฅผ ํฌํ•จํ•ด์„œ ๋ณด๋‚ธ๋‹ค.

์ฟ ํ‚ค - ์ƒ๋ช…์ฃผ๊ธฐ

๊ทธ๋Ÿผ ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‹ซํžˆ๋ฉด ์ฟ ํ‚ค๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋˜ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋œ ์ฟ ํ‚ค๋Š” ์–ธ์ œ๊นŒ์ง€ ์ €์žฅ๋˜๋Š”๊ฑธ๊นŒ?

์„œ๋ฒ„์—์„œ ์ฒ˜์Œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ด์ค„ ๋•Œ ์ฟ ํ‚ค์˜ ๋งŒ๋ฃŒ์ผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Set-Cookie: expire=Sat,26-Dec-2020 04:39:23 GMT // ๋งŒ๋ฃŒ์ผ์ด ๋˜๋ฉด ์‚ญ์ œ
Set-Cookie: max-age=3600 // 3600์ดˆ ์ดํ›„ ์‚ญ์ œ
  • ์„ธ์…˜ ์ฟ ํ‚ค: ๋งŒ๋ฃŒ๋‚ ์งœ๋ฅผ ์ƒ๋žตํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ์œ ์ง€
  • ์˜์† ์ฟ ํ‚ค: ๋งŒ๋ฃŒ๋‚ ์งœ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น ๋‚ ์งœ๊นŒ์ง€ ์œ ์ง€

์„œ๋ฒ„์—์„œ ๋งŒ๋ฃŒ์ผ์„ ์„ค์ •ํ•œ๋‹ค๊ณ  ํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฟ ํ‚ค ๋งŒ๋ฃŒ์ผ์ด ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ์ž๋™์œผ๋กœ ์‚ญ์ œํ• ๊นŒ?๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค์–ด์„œ ๊ฒ€์ƒ‰ํ–ˆ๋Š”๋ฐ ๋ธŒ๋ผ์šฐ์ €์˜ ์ฟ ํ‚ค ์ •์ฑ…์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

์ฟ ํ‚ค - ๋„๋ฉ”์ธ, ๊ฒฝ๋กœ

ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋œ ์ฟ ํ‚ค ์ •๋ณด๋Š” ํ•ญ์ƒ ์„œ๋ฒ„์— ์ „์†ก๋˜๋Š”๋ฐ ํ˜„์žฌ ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์—์„œ ๋ฐ›์•„ ์ €์žฅํ•œ ์ฟ ํ‚ค๋„ ํ•จ๊ป˜ ์ „์†ก๋˜๋Š”๊ฑธ๊นŒ? (๋‹น์—ฐํžˆ ๊ทธ๋Ÿฌ๋ฉด ์•ˆ๋˜๊ฒ ์ฃ ?)

domain=example.org // ๋ฌธ์„œ ๊ธฐ์ค€ ๋„๋ฉ”์ธ, ์„œ๋ธŒ ๋„๋ฉ”์ธ ํฌํ•จ -> dev.example.org
domain(empty) // ํ•ด๋‹น ๋„๋ฉ”์ธ์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ

๋„๋ฉ”์ธ๊ฐ’์„ ์ ์–ด์ฃผ์ง€ ์•Š๋”๋ผ๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๋‹น ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ด์ค€ ๋„๋ฉ”์ธ์— ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋งŒ ํ•ด๋‹น ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ฟ ํ‚ค - ๋ณด์•ˆ

ํ•ญ์ƒ ์„œ๋ฒ„์— ์ „์†ก๋˜๋Š” ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ์— ์ทจ์•ฝํ•˜๋‹ค. ์ตœ์†Œํ•œ์˜ ์ •๋ณด๋งŒ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.

  • Secure๋ฅผ ์ ์šฉํ•˜๋ฉด https์ธ ๊ฒฝ์šฐ์—๋งŒ ์ „์†ก
  • HttpOnly: HTTP ์ „์†ก์—๋งŒ ์‚ฌ์šฉ
  • SameSite: ์š”์ฒญ ๋„๋ฉ”์ธ๊ณผ ์ฟ ํ‚ค์— ์„ค์ •๋œ ๋„๋ฉ”์ธ์ด ๊ฐ™์€ ๊ฒฝ์šฐ์—๋งŒ ์ฟ ํ‚ค ์ „์†ก

Local Cocoapods ๋งŒ๋“ค๊ธฐ

Local Cocoapods ๋งŒ๋“ค๊ธฐ

์ด๋ฒˆ ์ •๋ฆฌ์—์„œ๋Š” Cocoapod์„ ์ด์šฉํ•ด์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์„ ๋•Œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์žฅ,๋‹จ์ ์— ๋Œ€ํ•ด์„œ๋Š” ์ •๋ฆฌํ•˜์ง€ ์•Š๊ณ  Cocoapod์„ ์ด๋Ÿฐ์‹์œผ๋กœ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค ๋Š๋‚Œ์œผ๋กœ ์ •๋ฆฌํ•ด๋ณผ ์˜ˆ์ •์ด๋‹ค.

1) ํ•„์š”์„ฑ

์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉด์„œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋””์ž์ธ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ๋„ ๋งŽ์•„์ง€๊ณ  ๊ทธ์— ๋Œ€์‘ ๋˜๋Š” ์ฝ”๋“œ๋“ค๋„ ๋งŽ์•„์ง€๋Š” ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ์—ˆ๋‹ค. ๋ฌผ๋ก  r.swift ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ๋ฆฌ์Šค์†Œ ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•ˆ๋“œ๋กœ์ด๋“œ์™€ ํŒŒ์ผ๋ช…์„ ๋งž์ถ”๋Š”๋ฐ ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค.

๋˜ํ•œ ๋””์ž์ธ ์‹œ์Šคํ…œ ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง€๋ฉด์„œ ๋””์ž์ธ์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฒ„ํŠผ, ํŒ์—…, ๋ฐ”ํ…€์‹œํŠธ ๋“ฑ๋“ฑ์ด ์ƒ๊ธฐ๋ฉด์„œ ์ด๋Ÿฐ ํŒŒ์ผ๋“ค์„ ํ•œ๋ฐ ๋ชจ์•„ ๋ชจ๋“ˆํ™” ์‹œํ‚ฌ ํ•„์š”์„ฑ์„ ๋Š๊ปด์„œ ๋ฐฉ๋ฒ•์„ ์ฐพ๋˜์ค‘ ์œ„์˜ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ๊ณผ์ •๊ณผ ๋˜ ์ƒˆ๋กญ๊ฒŒ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์ ๋“ค์„ ์•„์นด์ด๋น™ ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.


2) Local pod ๋งŒ๋“ค๊ธฐ

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-04-04_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_1 23 08

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-04-04_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_1 28 28

ํ„ฐ๋ฏธ๋„์—์„œ ์œ„์™€ ๊ฐ™์ด pod lib create {๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ช…} ์„ ์ž…๋ ฅํ•˜๋ฉด ํ”„๋กœ์ ํŠธ ํŒŒ์ผ์ด ํ•˜๋‚˜ ์ƒ์„ฑ๋œ๋‹ค.

2-1) podspec ํŒŒ์ผ ์„ค์ •ํ•˜๊ธฐ

Pod::Spec.new do |s|
  s.name             = 'BranUI'
  s.version          = '0.1.0'
  s.summary          = 'A short description of BranUI.'

  s.description      = <<-DESC
  TODO: Add long description of the pod here.
  DESC

# ๋ฏธ์„ค์ • ->
  s.homepage         = 'https://github.com/Brandnew-one/BranUI'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'Brandnew-one' => 'cold929@naver.com' }
  s.source           = { :git => 'https://github.com/Brandnew-one/BranUI.git', :tag => s.version.to_s }
# <- ๋ฏธ์„ค์ •

  s.ios.deployment_target = '15.0'

  s.source_files = 'BranUI/Classes/**/*'
  s.resources = "BranUI/Assets/*.xcassets"
  s.resource_bundles = {
    'BranUI' => ['BranUI/Assets/*']
  }
  s.dependency 'lottie-ios'
end

ํ˜„์žฌ cocoapods์„ ํ†ตํ•ด์„œ ๋งŒ๋“ค๊ณ  ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ spec์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜๋Š” ํŒŒ์ผ์ด๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๋ฐฐํฌํ•˜๋Š”๊ฒŒ ์•„๋‹Œ local๋กœ ์‚ฌ์šฉํ•  ์˜ˆ์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฏธ์„ค์ •์œผ๋กœ ํ‘œ๊ธฐ๋œ ๋ถ€๋ถ„์„ ์ œ์™ธํ•˜๊ณ  ์•„๋ž˜ ๋ถ€๋ถ„์— ์ง‘์ค‘ํ•ด๋ณด์ž.

ํ˜„์žฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋Š” ๋””์ž์ธ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์†Œ์Šค ํŒŒ์ผ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•˜๊ณ  motion๊ณผ ๊ฐ™์€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์œ„ํ•ด์„œ Lottie ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค„ ์˜ˆ์ •์ด๋‹ค.

Lottie๋ฅผ ์ถ”๊ฐ€ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— BranUI์˜ Podfile์—์„œ Lottie๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค!

use_frameworks!

platform :ios, '10.0'

target 'BranUI_Example' do
  pod 'BranUI', :path => '../'

  target 'BranUI_Tests' do
    inherit! :search_paths

    pod 'lottie-ios'
    
  end
end

2-2) Resoucre ํŒŒ์ผ ์„ค์ • ๋ฐ ๊ด€๋ จ ์ฝ”๋“œ ์ž‘์„ฑ

โ—๏ธpodspec ํŒŒ์ผ์„ ์„ค์ •ํ•  ๋•Œ, resouce์™€ source_file๋“ค์˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์—ˆ๋Š”๋ฐ ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฆฌ์†Œ์Šค ํŒŒ์ผ๊ณผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  .pbx ํŒŒ์ผ์ด ํ•ด๋‹น ํŒŒ์ผ์„ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค

Untitled

Untitled 1

Development Pods ๋””๋ ‰ํ† ๋ฆฌ์— ์ €์žฅ๋œ ํŒŒ์ผ๋“ค์€ ์œ„์™€ ๊ฐ™์ด podspec์— ์ •์˜๋œ ์œ„์น˜์— ์žˆ๋Š” ํŒŒ์ผ์ด์–ด์•ผ ํ•œ๋‹ค.

import Foundation

private class BranBundleClass {}

extension Bundle {
  class var branUI: Bundle {
    Bundle(for: BranBundleClass.self)
  }
}

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ Bundle ํŒŒ์ผ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ํ•ด์ค€๋‹ค.

import SwiftUI
import UIKit

extension Image {
  fileprivate static let bundle: Bundle = .branUI
}

extension UIImage {
  fileprivate static let bundle: Bundle = .branUI

  fileprivate convenience init(
    _ name: String,
    bundle: Bundle
  ) {
    self.init(named: name, in: bundle, compatibleWith: nil)!
  }
}

extension Image {
  public static let foodCart: Image = Image(
    "icons8-food-cart",
    bundle: bundle
  )
}

extension UIImage {
  public static let foodCart: UIImage = UIImage(
    "icons8-food-cart",
    bundle: bundle
  )
}

3) Local pod ์‚ฌ์šฉํ•˜๊ธฐ

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'BranTestProject' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Local Pods for BranTestProject
  pod 'BranUI', :path => "../BranUI/"

  # Pods for BranTestProject

end

์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€์ ธ์˜ค๋ฉด ๋œ๋‹ค.

.
โ”œโ”€โ”€ git
โ”‚   โ”œโ”€โ”€ BranTestProject
โ”‚   โ”‚   โ”œโ”€โ”€ ...
โ”‚   โ”‚   .
โ”‚   โ”‚   .
โ”‚   โ”‚   .
โ”‚   โ”‚   
โ”‚   โ”œโ”€โ”€ BranUI
โ”‚   โ”‚   โ”œโ”€โ”€ ...

์‹ค์ œ ํ”„๋กœ์ ํŠธ๋Š” https://github.com/Brandnew-one/LocalPod ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.