์ฑ„๋„ํ†ก ์•„์ด์ฝ˜

SwiftUI + TCA: ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋กœ ์™„์„ฑํ•˜๋Š” ์ฐจ์„ธ๋Œ€ iOS ์•„ํ‚คํ…์ฒ˜

๋ณต์žกํ•œ SwiftUI ์ƒํƒœ ๊ด€๋ฆฌ, TCA (The Composable Architecture)๋กœ ๊น”๋”ํ•˜๊ณ  ๊ฒฌ๊ณ ํ•œ ์•ฑ์„ ๋งŒ๋“œ์„ธ์š”. ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์˜ˆ์ œ๋กœ ํ•ต์‹ฌ๋งŒ ๋น ๋ฅด๊ฒŒ ๋ฐฐ์›๋‹ˆ๋‹ค.

(5.0) ์ˆ˜๊ฐ•ํ‰ 10๊ฐœ

์ˆ˜๊ฐ•์ƒ 65๋ช…

๋‚œ์ด๋„ ์ดˆ๊ธ‰

์ˆ˜๊ฐ•๊ธฐํ•œ ๋ฌด์ œํ•œ

๋จผ์ € ๊ฒฝํ—˜ํ•œ ์ˆ˜๊ฐ•์ƒ๋“ค์˜ ํ›„๊ธฐ

๋จผ์ € ๊ฒฝํ—˜ํ•œ ์ˆ˜๊ฐ•์ƒ๋“ค์˜ ํ›„๊ธฐ

5.0

5.0

ํ‘ธ๋ฅด๋Ž…๋Ž…

100% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

ํ”„๋กœ์ ํŠธ ๋„์ž…์— ๋„์›€์ด ๋งŽ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค :) ํ˜น์‹œ ์งˆ๋ฌธ๋„ ๋ฐ›์•„์ฃผ์‹œ๋‚˜์š”..??

5.0

JMK

100% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

์ข‹์€ ๊ฐ•์˜ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~ ์ถ”๊ฐ€ ๊ฐ•์˜ ๊ธฐ๋Œ€ํ•˜๊ณ  ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค~๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘

5.0

sclee

97% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

์ž˜๋ณด์•˜์Šต๋‹ˆ๋‹ค. tca ๋ง›๋ณด๊ธฐ๋กœ ์ข‹๋„ค์š”. ๋‹ค์Œ์— ์˜ฌ๋ฆฌ์‹œ๋Š” ๊ฐ•์˜๋ถ€ํ„ฐ๋Š” ํ™”์งˆ์ด ์กฐ๊ธˆ๋งŒ ์ข‹์•˜์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜๊ฐ• ํ›„ ์ด๋Ÿฐ๊ฑธ ์–ป์„ ์ˆ˜ ์žˆ์–ด์š”

  • TCA์˜ ํ•ต์‹ฌ ์š”์†Œ(State, Action, Reducer, Store)๋ฅผ ์ดํ•ดํ•˜๊ณ , SwiftUI ์•ฑ์˜ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ์ƒํƒœ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค.

  • SwiftUI์˜ ์ตœ์‹  Stack ๊ธฐ๋ฐ˜ ๋‚ด๋น„๊ฒŒ์ด์…˜๊ณผ Apple์˜ ์ฐจ์„ธ๋Œ€ ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์›Œํฌ์ธ SwiftData๋ฅผ TCA ์•„ํ‚คํ…์ฒ˜์— ํ†ตํ•ฉํ•˜์—ฌ ์‹ค์šฉ์ ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ์™„์„ฑํ•˜๋Š” ๊ฒฝํ—˜์„ ์–ป์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฏธ์ง€ ํ”ผ์ปค์™€ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ Reducer์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ swift-dependencies๋ฅผ ํ™œ์šฉํ•œ ์ตœ์‹  ์˜์กด์„ฑ ์ฃผ์ž… ๊ธฐ๋ฒ•์„ ์ตํž™๋‹ˆ๋‹ค.


SwiftUI + TCA: ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋กœ ์™„์„ฑํ•˜๋Š” ์ฐจ์„ธ๋Œ€ iOS ์•„ํ‚คํ…์ฒ˜

SwiftData, ์˜์กด์„ฑ ์ฃผ์ž…, ๋‚ด๋น„๊ฒŒ์ด์…˜๊นŒ์ง€ ํ˜„์—…์—์„œ ๋งˆ์ฃผํ•˜๋Š” ๊ธฐ์ˆ ์  ๊ณผ์ œ ์™„๋ฒฝ ์ •๋ณต


"๋‚ด SwiftUI ์•ฑ, ์™œ ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์กŒ์ง€? ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ต๋‹ค๊ณ ์š”? ๐Ÿคฏ"

์ ์  ์ปค์ง€๋Š” SwiftUI ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ์ƒํƒœ ๊ด€๋ฆฌ์— ํ˜ผ๋ž€์„ ๊ฒช๋Š” ๊ฐœ๋ฐœ์ž๋ถ„๋“ค์„ ์œ„ํ•ด, The Composable Architecture (TCA)๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ •๋ณตํ•˜๋Š” ๊ฐ•์˜๋ฅผ ์ค€๋น„ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฐ•์˜๋Š” ๋‹จ์ˆœํžˆ ์ด๋ก ๋งŒ ์„ค๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ๋งˆ์ฃผํ•  ์ˆ˜ ์žˆ๋Š” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ TCA + SwiftUI๋กœ ์–ด๋–ป๊ฒŒ ๊น”๋”ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š”์ง€, ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋‹จ๊ณ„๋ณ„๋กœ ์ƒ์„ธํžˆ ๋ณด์—ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


โœจ ์ด๋Ÿฐ ๋ถ„๋“ค๊ป˜ ๊ฐ•๋ ฅ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค!

  • SwiftUI ์•ฑ ๊ฐœ๋ฐœ ์ค‘์ธ ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž: ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ํŒจํ„ด์— ๋Œ€ํ•œ ๊ฐˆ์ฆ์„ ๋А๋ผ๋Š” ๋ถ„.

  • ์•„ํ‚คํ…์ฒ˜์— ๊ด€์‹ฌ ์žˆ๋Š” iOS ๊ฐœ๋ฐœ์ž: ์œ ์ง€๋ณด์ˆ˜์™€ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์ด ๋†’์€ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋ฐฐ์šฐ๊ณ  ์‹ถ์€ ๋ถ„.

  • TCA๋ฅผ ํ˜ผ์ž ๊ณต๋ถ€ํ•˜๋‹ค ์–ด๋ ค์›€์„ ๊ฒช๋Š” ๋ถ„: ์ด๋ก ๊ณผ ์‹ค์ œ ์ ์šฉ์˜ ๊ฐ„๊ทน์„ ๋ฉ”์šฐ๊ณ  ์‹ถ์€ ๋ถ„.

  • ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์˜ ํ€„๋ฆฌํ‹ฐ๋ฅผ ๋†’์ด๊ณ  ์‹ถ์€ ๋ถ„: ๊ฒฌ๊ณ ํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์•ฑ์„ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ๋ถ„.


๐Ÿš€ ์ด ๊ฐ•์˜๋ฅผ ํ†ตํ•ด ์–ป๊ฒŒ ๋  ๊ฒƒ๋“ค:

  1. TCA์˜ ํ•ต์‹ฌ ์ฒ ํ•™ ์™„๋ฒฝ ์ดํ•ด: State, Action, Reducer, Store๊ฐ€ ์™œ ํ•„์š”ํ•˜๋ฉฐ ์–ด๋–ป๊ฒŒ ์œ ๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



  2. ๋ณต์žกํ•œ SwiftUI ์ƒํƒœ ๊ด€๋ฆฌ ํ•ด๊ฒฐ: ๋ณต์žกํ•œ UI ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ TCA๋ฅผ ํ†ตํ•ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ์•ˆ์ •์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋…ธํ•˜์šฐ๋ฅผ ์ฒด๋“ํ•ฉ๋‹ˆ๋‹ค. TCA์˜ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๋…ธํ•˜์šฐ๋ฅผ ๋ฐฐ์›๋‹ˆ๋‹ค.



  3. Scope๋ฅผ ํ™œ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋“ˆํ™”: ํ•˜๋‚˜์˜ ๊ฑฐ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๋…๋ฆฝ์ ์ด๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ž์‹(Child) ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ , ๋ถ€๋ชจ-์ž์‹ ๊ฐ„์˜ ์ƒํƒœ์™€ ์•ก์…˜์„ ์•ˆ์ „ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งˆ์Šคํ„ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์•ฑ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.



  4. ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ ํ™•๋ณด: TCA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฒ„๊ทธ๋ฅผ ์ค„์ด๊ณ  ์•ˆ์ •์ ์ธ ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ตํž™๋‹ˆ๋‹ค.

  5. ๋ชจ๋˜ํ•œ ๋‚ด๋น„๊ฒŒ์ด์…˜ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„: ํ™”๋ฉด์„ ๋ฐ€๊ณ  ๋‹น๊ธฐ๋Š” 'Stack ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜'๊ณผ ์‹œํŠธ, ํŒ์—… ๋“ฑ์„ ๋‹ค๋ฃจ๋Š” 'ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜'์„ ๋ชจ๋‘ ๋งˆ์Šคํ„ฐํ•ฉ๋‹ˆ๋‹ค. TCA์˜ Scope, NavigationStackStore, ifLet ๋“ฑ์„ ํ™œ์šฉํ•ด ์–ด๋–ค ๋ณต์žกํ•œ ํ™”๋ฉด ํ๋ฆ„๋„ ๋ช…์พŒํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค.



  6. ํ™•์žฅ์„ฑ ๋†’์€ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„: ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ค„์ด๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” TCA์˜ ์žฅ์ ์„ ์‹ค์ „์—์„œ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.



  7. ์‹ค์ „ ํ”„๋กœ์ ํŠธ ๊ฒฝํ—˜: ์ด๋ฏธ์ง€ ํ”ผ์ปค, API ํ†ต์‹ ๊ณผ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ Reducer์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ , swift-dependencies๋ฅผ ํ™œ์šฉํ•œ ์ตœ์‹  ์˜์กด์„ฑ ์ฃผ์ž… ๊ธฐ๋ฒ•์„ ์ตํž™๋‹ˆ๋‹ค.




์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์„ ๋งŒ๋“ค๊ฒŒ ๋ ๊นŒ์š”? ๐Ÿš€


์ด๋ก  ํ•™์Šต์„ ๋„˜์–ด, ์‹ค์ œ ์ž‘๋™ํ•˜๋Š” '๋งˆ์ดํŽ˜์ด์ง€', '๊ฒ€์ƒ‰' ๊ธฐ๋Šฅ ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํ•จ๊ป˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค.


  • ๊ธฐ๋ณธ UI ๋ฐ ๋ฐ์ดํ„ฐ ์—ฐ๋™: SwiftUI์™€ SwiftData๋ฅผ ์‚ฌ์šฉํ•ด ์„ค์ • ๋ชฉ๋ก์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • Stack ๊ธฐ๋ฐ˜ ๋‚ด๋น„๊ฒŒ์ด์…˜: ๋ชฉ๋ก์—์„œ ์ƒ์„ธ ํŽ˜์ด์ง€(์ด๋ฆ„ ์ˆ˜์ •, ์ด๋ฉ”์ผ ์ˆ˜์ •, ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ)๋กœ ์ง„์ž…ํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด๋ฆ„/์ด๋ฉ”์ผ ์ˆ˜์ •: TextField ๋ฐ”์ธ๋”ฉ๊ณผ AlertState๋ฅผ ํ™œ์šฉํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ํ™•์ธ ์•Œ๋ฆผ์„ ๋„์›๋‹ˆ๋‹ค.

  • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ: PhotosUI๋ฅผ ์—ฐ๋™ํ•ด ๊ฐค๋Ÿฌ๋ฆฌ์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜๊ณ , LazyVGrid๋ฅผ ํ†ตํ•ด ๋ณด์—ฌ์ฃผ๋ฉฐ, ์„ ํƒํ•œ ์ด๋ฏธ์ง€๋กœ ํ”„๋กœํ•„์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฐ•๋ ฅํ•œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„:

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

    • ifLet์„ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ UI: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ๊ฒฐ๊ณผ ๋ชฉ๋ก UI๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ TCA์˜ ifLet ์Šค์ฝ”ํ”„๋ฅผ ํ†ตํ•ด ์šฐ์•„ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

    • ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์•„์ดํ…œ์„ ํƒญ ํ–ˆ์„ ๋•Œ, ํ•ด๋‹น ์•„์ดํ…œ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋กœ์ง์„ ๊ฒฝํ—˜ํ•˜๋ฉฐ Stack ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜๊ณผ์˜ ์ฐจ์ด์ ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.


๋” ์ด์ƒ ๋ณต์žกํ•œ ์ฝ”๋“œ๋กœ ๊ณ ๋ฏผํ•˜์ง€ ๋งˆ์„ธ์š”! ์ด ๊ฐ•์˜์™€ ํ•จ๊ป˜๋ผ๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์˜ SwiftUI ์•ฑ ๊ฐœ๋ฐœ ์‹ค๋ ฅ์€ ํ•œ ๋‹จ๊ณ„ ๋” ๋„์•ฝํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. TCA(swift-composable-architecture)๋กœ ๊ฒฌ๊ณ ํ•˜๊ณ  ์•„๋ฆ„๋‹ค์šด ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”! ๐Ÿš€


์ด๋Ÿฐ ๋ถ„๋“ค๊ป˜
์ถ”์ฒœ๋“œ๋ ค์š”

ํ•™์Šต ๋Œ€์ƒ์€
๋ˆ„๊ตฌ์ผ๊นŒ์š”?

  • ๊ธฐ์กด SwiftUI์˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐฉ์‹(@State, @Binding, ObservableObject)์— ํ•œ๊ณ„๋ฅผ ๋А๋ผ๊ณ , ๋ณด๋‹ค ์ฒด๊ณ„์ ์ธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋„์ž…ํ•˜๊ณ  ์‹ถ์€ ๊ฐœ๋ฐœ์ž

  • ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ ๊ธฐ๋ฐ˜์˜ ํ•™์Šต์„ ํ†ตํ•ด TCA์˜ ์ด๋ก ๊ณผ ์‹ค์ œ๋ฅผ ํ•จ๊ป˜ ๊ฒฝํ—˜ํ•˜๊ณ  ์‹ถ์€ ๊ฐœ๋ฐœ์ž

  • ์•ฑ์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ ธ๋„ ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์šฉ์ดํ•œ, ํ™•์žฅ์„ฑ ๋†’์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๊ณ  ์‹ถ์€ ๊ฐœ๋ฐœ์ž

์„ ์ˆ˜ ์ง€์‹,
ํ•„์š”ํ• ๊นŒ์š”?

  • Swift ๊ธฐ์ดˆ

์•ˆ๋…•ํ•˜์„ธ์š”
๋ค๋ฒจ๋กœํผ์ž…๋‹ˆ๋‹ค.

481

๋ช…

์ˆ˜๊ฐ•์ƒ

34

๊ฐœ

์ˆ˜๊ฐ•ํ‰

28

๊ฐœ

๋‹ต๋ณ€

4.6

์ 

๊ฐ•์˜ ํ‰์ 

5

๊ฐœ

๊ฐ•์˜

6๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž ๋ค๋ฒจ๋กœํผ์ž…๋‹ˆ๋‹ค

ํ˜„์—…์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ๋Š” ๊ฐ•์˜

์ดˆ์ค‘๊ธ‰ ๋ ˆ๋ฒจ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฐ•์˜๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค

 

 

๋”๋ณด๊ธฐ

์ปค๋ฆฌํ˜๋Ÿผ

์ „์ฒด

36๊ฐœ โˆ™ (5์‹œ๊ฐ„ 3๋ถ„)

ํ•ด๋‹น ๊ฐ•์˜์—์„œ ์ œ๊ณต:

์ˆ˜์—…์ž๋ฃŒ
๊ฐ•์˜ ๊ฒŒ์‹œ์ผ: 
๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ์ผ: 

์ˆ˜๊ฐ•ํ‰

์ „์ฒด

10๊ฐœ

5.0

10๊ฐœ์˜ ์ˆ˜๊ฐ•ํ‰

  • ๊ณ ๋ฏผ์„๋‹˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
    ๊ณ ๋ฏผ์„

    ์ˆ˜๊ฐ•ํ‰ 3

    โˆ™

    ํ‰๊ท  ํ‰์  5.0

    5

    62% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

    • ํ‘ธ๋ฅด๋Ž…๋Ž…๋‹˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
      ํ‘ธ๋ฅด๋Ž…๋Ž…

      ์ˆ˜๊ฐ•ํ‰ 4

      โˆ™

      ํ‰๊ท  ํ‰์  5.0

      5

      100% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

      ํ”„๋กœ์ ํŠธ ๋„์ž…์— ๋„์›€์ด ๋งŽ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค :) ํ˜น์‹œ ์งˆ๋ฌธ๋„ ๋ฐ›์•„์ฃผ์‹œ๋‚˜์š”..??

      • ๋ค๋ฒจ๋กœํผ
        ์ง€์‹๊ณต์œ ์ž

        ๋„ค ๊ทธ๋Ÿผ์š” ์งˆ๋ฌธ ํ•ด์ฃผ์„ธ์š”! ํ”„๋กœ์ ํŠธ์— ๋„์›€์„ ๋“œ๋ฆฌ๊ฒŒ๋˜์–ด ์˜๊ด‘์ž…๋‹ˆ๋‹ค!

      • ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์ฒ˜์Œ TCA๋ฅผ ์ ‘ํ–ˆ๋Š”๋ฐ๋„ ๊ฐ•์˜๊ฐ€ ์›Œ๋‚™ ์ž˜ ๋˜์–ด ์žˆ์–ด์„œ ์‹œ๊ฐ„์ด ์กฐ๊ธˆ ๊ฑธ๋ฆฌ๊ธด ํ–ˆ์ง€๋งŒ ๋ฌด๋‚œ(?)ํ•˜๊ฒŒ ์ดํ•ด๋„ ํ–ˆ๊ณ , ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—๋„ ์ ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ•์˜์—์„œ ๋‹ค๋ฃฌ ๊ฒƒ์ฒ˜๋Ÿผ ๋งˆ์ดํŽ˜์ด์ง€ โ†’ [์ด๋ฉ”์ผ / ํ”„๋กœํ•„ / ๋‹‰๋„ค์ž„] ์ˆ˜์ • ํ™”๋ฉด์ฒ˜๋Ÿผ ๋‹จ์ผ ๊นŠ์ด์˜ ํ™”๋ฉด ์ด๋™์€ ์ดํ•ด๊ฐ€ ์ž˜๋˜๊ณ , ๊ตฌํ˜„๋„ ์ž˜ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ ์•ฑ์—์„œ๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ์ฒ˜๋Ÿผ ๊ฒŒ์‹œ๋ฌผ โ†’ ์‚ฌ์šฉ์ž A ํ”„๋กœํ•„ โ†’ ์‚ฌ์šฉ์ž A์˜ ํŒ”๋กœ์šฐ ๋ฆฌ์ŠคํŠธ โ†’ ์‚ฌ์šฉ์ž B ํ”„๋กœํ•„ โ†’ ์‚ฌ์šฉ์ž B์˜ ํŒ”๋กœ์šฐ ๋ฆฌ์ŠคํŠธโ€ฆ ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ณ„์† ๊นŠ์–ด์ง€๋Š” ํ™”๋ฉด ์ด๋™ ๊ตฌ์กฐ๊ฐ€ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์—์„œ ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ๊ฐ•์˜์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์„ ๋†“์นœ ๊ฑด์ง€, ์•„๋‹ˆ๋ฉด ์ด๋Ÿฐ ๋‹ค์ธต(?), ์ค‘์ฒฉ(?) ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒจํ„ด์€ ์›๋ž˜ TCA์—์„œ ์กฐ๊ธˆ ๊นŒ๋‹ค๋กœ์šด ํŽธ์ธ์ง€ ์กฐ์–ธ์„ ์–ป๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค! ํ˜น์‹œ ๋ชฐ๋ผ์„œ ํ˜„์žฌ ๊ตฌํ˜„ํ•œ ๋ฐฉ๋ฒ•์„ ๋ง์”€๋“œ๋ฆฌ๋ฉด ๋งˆ์ดํŽ˜์ด์ง€์— ๊ด€ํ•œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์žฌํ™œ์šฉ ๊ฐ€๋Šฅํ•  ์ค„ ์•Œ์•˜๋Š”๋ฐ, ๊ทธ๋Ÿฌ๊ธฐ๋งŒํ•˜๋ฉด ํ„ฐ์ ธ๋ฒ„๋ ค์„œ ์ง€๊ธˆ์€.. ๋งˆ์ดํŽ˜์ด์ง€์—์„œ ์ด๋™๊ฐ€๋Šฅํ•œ ์ผ€์ด์Šค๋ฅผ [ํŒ”๋กœ์šฐ/ํŒ”๋กœ์ž‰ ๋ฆฌ์ŠคํŠธ, ๊ฒŒ์‹œ๋ฌผ] ํ™”๋ฉด ์œผ๋กœ ๊ฐ€์ •ํ•œ๋‹ค๋ฉด ์˜ˆ๋ฅผ ๋“ค์–ด 1๋ฒˆ ํƒญ์ด ๊ฒŒ์‹œ๊ธ€ ๊ด€๋ จ์ด๋ผ๊ณ  ํ•œ๋‹ค๋ฉด ๊ฒฐ๊ตญ ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋“ค์–ด๊ฐ€์•ผํ•˜์ž–์•„์š”? 2๋ฒˆ ํƒญ์ด ๋ฆด์Šค/์‡ผ์ธ  ๊ด€๋ จํƒญ์ด๋ผ๊ณ  ํ•œ๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ๋„ ๊ฒฐ๊ตญ ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋“ค์–ด๊ฐ€์•ผํ•˜๊ตฌ์š” ๊ทธ๋Ÿฐ๋ฐ ์ง€๊ธˆ์€ ๊ฐ ํƒญ ํ™”๋ฉด์—์„œ ๋งˆ์ดํŽ˜์ด์ง€ ํ™”๋ฉด์ „ํ™˜ ์ผ€์ด์Šค๋ฅผ ์ „๋ถ€ ๋™์ผํ•˜๊ฒŒ ๋ณต๋ถ™ํ•ด์„œ ์‚ฌ์šฉ ์ค‘์ด์—์š” ใ…œ

      • ๋ค๋ฒจ๋กœํผ
        ์ง€์‹๊ณต์œ ์ž

        ๋‹ต๋ณ€์— ์•Œ๋žŒ์„ ๋ชป๋ด์„œ ๋„ˆ๋ฌด ๋Šฆ์–ด์กŒ๋„ค์š” ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.. ํ„ฐ์ ธ๋ฒ„๋ฆฐ ์›์ธ์€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์žฌํ™œ์šฉ์ด ๊ฐ€๋Šฅํ•œ๋ฐ์š” ์˜ˆ๋กœ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ๋‹ด๋‹นํ•˜๋Š” ํ•˜์œ„ ๋ฆฌ๋“€์„œ๋ฅผ ๋งŒ๋“ค์–ด ๋‘๊ณ  ํ•ด๋‹น ๋ฆฌ๋“€์„œ์— ์ง„์ž…ํ•  ์Šค์ฝ”ํ”„๋ฅผ ๋ชจ๋‘ ์ง€์ •ํ•ด์ค€๋’ค์— Scope(state: \.profile, action: \.profile) { ProfileFeature() } ๋ถ€๋ชจ ํƒญ๋งˆ๋‹ค StackState๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ๋ ๊ฑฐ๊ฐ™์Šต๋‹ˆ๋‹ค state.path.append(.profile(ProfileFeature.State(userId: "me"))) ์—ฌ๊ธฐ์—๋Š” ์ค„๋„˜๊น€์ด ์ž˜ ๋˜์ง€์•Š์•„ ์ฝ๊ธฐ ์–ด๋ ค์šฐ์‹ค๊ฑฐ๊ฐ™๋„ค์š”ใ… ใ…  @Reducer struct Path { @ObservableState enum State: Equatable { case profile(ProfileFeature.State) } enum Action { case profile(ProfileFeature.Action) } var body: some ReducerOf<Self> { Scope(state: \.profile, action: \.profile) { ProfileFeature() } } } @Reducer struct HomeTabFeature { @ObservableState struct State: Equatable { var path = StackState<Path.State>() } enum Action { case path(StackAction<Path.State, Path.Action>) case didTapMyProfile } var body: some ReducerOf<Self> { Reduce { state, action in switch action { case .didTapMyProfile: state.path.append(.profile(ProfileFeature.State(userId: "me"))) return .none ...

    • ๊น€ํšจ๊ฑด๋‹˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
      ๊น€ํšจ๊ฑด

      ์ˆ˜๊ฐ•ํ‰ 1

      โˆ™

      ํ‰๊ท  ํ‰์  5.0

      5

      32% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

      • Lim Jeeun๋‹˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
        Lim Jeeun

        ์ˆ˜๊ฐ•ํ‰ 1

        โˆ™

        ํ‰๊ท  ํ‰์  5.0

        5

        100% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

        • Hewbie๋‹˜์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€
          Hewbie

          ์ˆ˜๊ฐ•ํ‰ 25

          โˆ™

          ํ‰๊ท  ํ‰์  4.2

          5

          32% ์ˆ˜๊ฐ• ํ›„ ์ž‘์„ฑ

          ๋ค๋ฒจ๋กœํผ๋‹˜์˜ ๋‹ค๋ฅธ ๊ฐ•์˜

          ์ง€์‹๊ณต์œ ์ž๋‹˜์˜ ๋‹ค๋ฅธ ๊ฐ•์˜๋ฅผ ๋งŒ๋‚˜๋ณด์„ธ์š”!

          ๋น„์Šทํ•œ ๊ฐ•์˜

          ๊ฐ™์€ ๋ถ„์•ผ์˜ ๋‹ค๋ฅธ ๊ฐ•์˜๋ฅผ ๋งŒ๋‚˜๋ณด์„ธ์š”!

          โ‚ฉ69,300