Great App ์ ๋ง๋ค๊ธฐ ์ํ ๊ฐ์ฅ ๋น ๋ฅธ ๋๊ตฌ SwiftUI
UI๋ ์ฑ ์ ์์ ์์ด์ ๋น ์ง ์ ์๋ ์์์ด๋ค. UI์๋ ํ ์คํธ ํ๋, ๋ฒํผ ๋ฟ๋ง ์๋๋ผ ๋คํฌ๋ชจ๋, ๋ก์ปฌ๋ผ์ด์ ์ด์ ์ง์ ๋ฑ๋ฑ ๋ค์ํ ์์๊ฐ ๋ค์ด๊ฐ๊ฒ๋๋ค. ์ด๋ UI์ ์ธ ์์๋ฅผ ํฌ๊ฒ ๋ ๊ฐ์ง๋ก ๋๋ ์ ์๋๋ฐ ๋ฒํผ, ํ ์คํธํ๋, ๋ผ๋ฒจ๊ณผ ๊ฐ์ ์ด๋ฏธ ์ ํํ๋, ๊ณ ์ ๋ (Basic Feature) UI์ ์ ๋๋ฉ์ด์ ํจ๊ณผ, ๋ค์ด๋๋ฏน ํ์ , ๋ก์ปฌ๋ผ์ด์ ์ด์ ๊ณผ ๊ฐ์ ์ปค์คํฐ๋ง์ด์ง์ ์ธ(Custom Features) ์์๊ฐ ์๋ค. "ํ๋ฅญํ"์ฑ์ผ ์๋ก ์ ํํ๋ UI์์๋ณด๋ค ์ด๋ฌํ ์ปค์คํฐ๋ง์ด์งํ ์์๊ฐ ๋ง์์ง๊ฒ ๋๋ค.
์ ํ์ ๊ฐ๋ฐ์๊ฐ Custom Features UI์ ์ง์คํ ์ ์๋๋ก ์ ์ธํ/๋ฐ์ํ ๋๊ตฌ์ธ SwiftUI๋ฅผ ๋ง๋ค์ด ๊ฐ๋ฐ์๊ฐ ๋น ๋ฅด๊ณ ์ฝ๊ฒ Basic Features๋ฅผ ๋ง๋๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ค.
SwiftUI ๊ฐ View ๋ฅผ ๊ทธ๋ฆฌ๋ ์๋ฆฌ
์ฌ์ฉ์๊ฐ ๋ณด๊ฒ๋๋ ์ฑ์ ๊ฐ์ฅ ์๋จ์๋ ์ธ์ ๋ View๊ฐ ์๋ค. macOS ์ AppKit ์๋ NSView๊ฐ ์๊ณ iOS์ UIKit ์๋ UIView๊ฐ ์๋ ๊ฒ์ฒ๋ผ SwiftUI์๋ View ๊ฐ ์กด์ฌํ๋ค.
A View defines a piece of UI
View๋ SwiftUI๊ฐ ๊ทธ๋ฆฌ๋ UI์ ๊ฐ์ฅ ๊ธฐ์ด์ ์ธ ๋ธ๋ก ์ธํฐํ์ด์ค์ด๋ค. ํ๋ฉด์ ๋ณด์ด๋ ๋ชจ๋ ํฝ์ ์ ๋ทฐ์ ํฌํจ๋๋ค๊ณ ๋ณผ ์ ์๋ค.
์ด๋ฌํ ๋ทฐ๋ ๊ณ์ธต๊ตฌ์กฐ๋ฅผ ์์ฑํ๋ฉฐ ํฉ์ฑ(Compositioning)๋๋ค.
์ ์ค์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด ์ฝ๋๊ฐ ๋ค์ฌ์ฐ๊ธฐ์ ๋ฐ๋ผ ๊ณ์ธต๊ตฌ์กฐ๊ฐ ๋ง๋ค์ด์ง๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
UIKit๊ณผ ๋น๊ตํ์ ๋ addSubview() ๋ฉ์๋๊ฐ ์๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋๋ฐ ์ด๋ SwiftUI๊ฐ ์ ์ธํ ํ๋ ์์ํฌ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ๋ง์ ์๋ฏธ์ ๋ํด ์กฐ๊ธ๋ ์์ธํ ๋ค์ฌ๋ค๋ณด์
Imperative UI
์๋ณด์นด๋ ํ ์คํธ๋ฅผ ์๋ก ๋ค์ด๋ณด์. ๊ธฐ์กด UIKit๊ณผ ๊ฐ์ ์ ์ฐจํ(Imperative) ํ๋ ์์ํฌ๋ ์๋ณด์นด๋ ํ ์คํธ๋ฅผ ๋ง๋ค๊ธฐ์ํด ์๋์ ๊ฐ์ ์์๋๋ก ์งํํ๋ค.
1. ์ฌ๋ฃ์ค๋น ํ๊ธฐ: ์๋ณด์นด๋, ๋นต, ๋ฒํฐ, ์๊ธ, ํ์ถ etc
2. ์๋ฆฌ๋๊ตฌ ์ค๋นํ๊ธฐ: ํ ์คํธ๊ธฐ๊ณ, ์ ์, ๋ฒํฐ์นผ
3. ๋นต์ ์๊ฒ ์ฐ๊ธฐ
4. ์ ์์ ๋นต์ ๋๊ธฐ
5. ํ ์คํธ ์์ ๋ฒํฐ๋ฅผ ์๊ฒ ํด๊ธฐ
6. ์๋ณด์นด๋ ์ฐ๊ธฐ
7. ์๋ณด์นด๋ ์จ์ ์ ๊ฑฐํ๊ธฐ
...
๋๊ฐ์ ์์ ์ ์ ์ฐจํ(Imperative)์ด ์๋ ์ ์ธํ(Declarative)์ผ๋ก ์๋ณด์นด๋ ํ ์คํธ๋ฅผ ๋ง๋ค์ด๋ณด์
1. "๋ ๋ฒํฐํ๊ณ ์๊ธํ๊ณ ํ์ถ๋ค์ด๊ฐ ์๋ณด์นด๋ ํ ์คํธ๊ฐ ํ์ํจ~"
2. "์ ๊ทธ๋ฆฌ๊ณ ํ ์คํธ ๋๊ฐ์ ์ผ๋ก ์๋ผ์ค~"
3. "ํด ์ค."
์์ ๊ฐ์ด ์ ์ฐจํ์ ์ฃผ๋ฌธ์ฌํญ์ ์๋์๋ถํฐ ๊พธ์ญ๊พธ์ญ ํ๋ํ๋ ์ค๋นํด๋๊ฐ๊ณ ์ ์ธํ์ ์ด๋ฏธ ๋ง๋ค์ด์ง ์์ ๋ธ๋ก๋ค์ ์ด์ฉํด์ ํด์ค-ํด์ค-ํด์ค์ ์ฐ์์ผ๋ก ์ฃผ๋ฌธ์ด ๋ค์ด๊ฐ๋ค. ๋ฌผ๋ก ์ ์ธํ์ ๋๊น์ง ํํค์น๋ฉด ๋ฐ๋์ ์ ์ฐจํ์ผ๋ก ๊ตฌ์ฑ๋์ด ์๊ฒ ์ง๋ง ์์ฐ์ฑ์ ๊ณ ๋ คํ๋ฉด ํน์ ์ํฉ์ด ์๋ ์ด์ ์ ์ธํ ์ฐ๋๊ฒ ์ ์ ๊ฑด๊ฐ์ ์ด๋กญ๋ค.
View Container Syntax
ํ์ง๋ง ์ด๋ป๊ฒ ์ ์ธํ UI๋ฅผ ๊ตฌํํ์๊น? VStack ์ ์์๋ก ์์๋ณด์
VStack ๋ด๋ถ์์๋ @ViewBuilder (Swift Attrubutes) ๊ฐ ๋ถ์ด์๋ ํด๋ก์ ๋ฅผ ํตํด Content๋ฅผ ๋ฆฌํดํ๋ค.
@viewBuilder ๋?
@viewBuilder๋ @resultBuilder์ ํ ์ข ๋ฅ์ด๋ค. @resultBuilder๋ Swift 5.4์ ์ถ๊ฐ๋ Attribute์ด๋ค
Attribute๋ ์ฝ๋์์ @๋ก ํ์๋๋ฉฐ ์ฝ๋์ ๋ํด ์ปดํ์ผ๋ฌ์๊ฒ ์ถ๊ฐ ์ ๋ณด๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ค.
@resultBuilder ๋ ์ฌ๋ฌ ๊ฒฐ๊ณผ๋ฌผ์ ํ๋์ ๊ฒฐ๊ณผ๋ฌผ๋ก ์กฐํฉํด์ฃผ๋ ์ญํ ์ ์ํํ๋ค.
@resultBuilder ๋ ๋์ด๋ ๋ฐ์ดํฐ๋ค์ ๋ฌธ๋งฅ๊ณผ ์๋ฏธ๋ฅผ ๋ํด์ฃผ๊ณ ํด์ํ๋ buildBlock() ๋ฉ์๋๋ฅผ ํตํด ์ํํ๋ค.
๋ค์๋งํด @resultBuilder๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ตฌ์กฐ์ฒด๋ ๋ฐ๋์ buildBlock() ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
@resultBuilder๋ฅผ ํตํด ์ฌ๋ฌ๊ฐ์ง ์ฌ๋ฃ๋ฅผ ์ธ๋ถ์์ ๋ฏธ๋ฆฌ ์ ํด๋ ๊ท์น์ผ๋ก ๊น๋ํ๊ฒ ํฉ์น๋ ๊ฒ์ด๋ค.
๋ค์ @viewBuilder๋ก ๋์์, ์ฌ๋ฌ๊ฐ์ง ๋ทฐ(์ต๋ 10๊ฐ)๋ฅผ ์ธ๋ถ์์ ์ง์ ํ ๊ท์น์ ๋ฐ๋ผ ํ๋์ ๋ทฐ๋ก ํฉ์น๋ ์ญํ ์ ์ํํ๋ค.
์ฌ๋ด์ด์ง๋ง ์์ ๊ฐ์ @viewBuilder๋ฅผ ์ด์ฉํ๋ฉด ์ฌ์ฌ์ฉ ๋ทฐ๋ฅผ ๋ง๋๋๋ฐ ๋งค์ฐ ์ ์ฉํ๋ค. (feat. ์ ๋๋ฆฌ)
VStack ์ฒ๋ผ init์ @viewBuilder attribute๋ฅผ ๋ฐ๋ ํด๋ก์ ๋ฅผ ๋ฃ์ด์ฃผ๋ฉด
์ฌ์ฌ์ฉ ๋ทฐ์ ๋ํด ์ถ๊ฐ์ ์ธ ๋ทฐ๋ฅผ ์๋น์ ๊ฐ์ฒด์์ ์ฌ์ฉํ ์ ์๋ค.
์ด๋ ์ฃผ์ํ ์ ์ ํธ๋ ์ผ๋ง ํด๋ก์ ์ฒ๋ผ ์ด๋ฆ์์ด (Content) ๋ฐ์ ๋๋
์์ฑ์ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ๋ง์ง๋ง์ ๋ฃ์ด์ฃผ์ด์ผ ํ๋ค.
WWDC ๋ด์ฉ์ผ๋ก ๋์์ค๋ฉด, VStack์ @viewBuilder attribute๋ฅผ ๋ฐ๊ณ ์๊ณ Content ํ์ ์ ๋ฆฌํดํ๋ ํด๋ก์ ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๋ ๋ค๋ฉด Content ํ์ ์ ๋ฌด์์ผ๊น? Content ํ์ ์ SwiftUI์ ์ปจํ ์ด๋์ ํ์๋๋ ์ปจํ ์ธ ๋ฅผ ์๋ฏธํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๋๋ฆญ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ค ์ปจํ ์ธ ๋ ์ฌ ์ ์๋ค.
@viewBuilder content: () -> Content
์ด ํ ์ค์ ๋ค์ ํ ๋ฒ ํด์ํด๋ณด์
@viewBuilder๋ฅผ ํตํด ์ฌ๋ฌ๊ฐ์ง ์์๊ฐ ๋ค์ด์ ๋ฏธ๋ฆฌ์ ํ ๊ท์น์์ํด ์กฐํฉ๋์ด ํ๋์ ๊ฒฐ๊ณผ๋ฌผ๋ก ๋์จ๋ค. ์ฌ๊ธฐ์ "์์"๋ Content ํ์ ์ด๋ผ๋ ์ผ์ข ์ ์ ๋๋ฆญ ํ์ ์ผ๋ก ๋ค์ํ ํ์ ๋ค์ด ์ฌ ์ ์๋ค. ๋ํ ์์ฑ์ ๋ง์ง๋ง์ ์ ์ธ๋์ด ์๋น์๊ฐ ์ด๋ถ๋ถ์ ์ฌ์ฉํ ๋๋ ํธ๋ ์ผ๋ง ํด๋ก์ ธ ํํ๋ก ์ด๋ฆ์๋ ํจ์๋ก ์ ์ธ๋๋ค. ์ด๋ฐ ๊ณผ์ ์ ๊ฑฐ์ณ ...
์ด์ ๊ฐ์ ์๋ฆ๋ต๊ณ ๊ฐ๊ฒฐํ ์ฝ๋๋ก UI๋ฅผ ๊ตฌํํ๋ค.
ํ์ง๋ง ์ ์ฝ๋๋ฅผ ๋ณด๋ฉด $๋ฌ๋ฌ ์ฌ๋ณผ์ด ์๋ ์ฝ๋๋ฅผ ํ์ธํ ์ ์๋ค. ๋ ์ ๊ฑด ๋ฌด์์ผ๊น?
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด Property Wrapper์ ๋ฐ์ธ๋ฉํ๊ธฐ ์ํด์๋ $์ฌ๋ณผ์ด ํ์ํ๋ค. Property wrapper ๋ ๊ตฌ์กฐ์ฒด๋ก ์ ์ธ๋๊ณ ๋ด๋ถ์๋ ๋น์ฐํ ๊ฐ์ด ์๋ค. ํ๋กํผํฐ ๋ํผ ๋ด๋ถ์ ๊ฐ์ ์ธ๋ถ์์ ๋ฐ์ธ๋ฉํ์ฌ ์ฌ์ฉํ๊ณ ์ถ์ ๋๋ $ ์ฌ๋ณผ์ ์์์ ์จ์ค๋ค. @State ํ๋กํผํฐ ๋ํผ์ ๊ฐ์ ๋ฐ์ธ๋ฉํ์ฌ ๋ฐ์ดํฐ ํ๋ก์ฐ๋ฅผ ๊ด๋ฆฌํ๋ค ๋ ์์ธํ ์ค๋ช ์ ์ถํ Property wrapper ๋ฅผ ์๊ฐํ๋ WWDC ์ธ์ ์์ ๋ค๋ฃจ์ด๋ณด๋ คํ๋ค.
Modifier
๋ทฐ๋ฅผ ์งค ๋๋ ๊ธฐ๋ณธ์ ์ธ View ๋ฉ์ด๋ฆฌ์ ๋ฉ์ด๋ฆฌ๋ฅผ ์์ ํด๋๊ฐ๋ ๊ณผ์ ์ ํตํด ์ํ๋ ๋ทฐ๋ฅผ ๋ง๋ ๋ค.
๋ฒํผ, ํ ์คํธํ๋, ๋ผ๋ฒจ๊ณผ ๊ฐ์ ๊ธฐ๋ณธ๋ฉ์ด๋ฆฌ๋ฅผ Primitive View ๋ผ ๋ถ๋ฅด๊ณ
Primitive View๋ฅผ ์กฐ๊ธ์ฉ ์์ ํด์ ์ํ๋ ๋ทฐ๋ก ๋ง๋ค๊ฒ๋ ๋์์ ์ฃผ๋ ๋ฉ์๋๋ฅผ Modifer๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๋จผ์ Modifer์ ๋ํด์ ์์๋ณด์
modifier ๋ ๊ธฐ๋ณธ์ ์ผ๋ก View ํ์ ์ ๋ฆฌํดํ๋ ๋น๋ํจํด์ผ๋ก ๊ตฌํ๋์ด์๋ค. ๋ฐ๋ผ์ ๋ทฐ ๊ณ์ธต์ ์ด์ฉํด์ ๊ฐ๊ฒฐํ ์ฝ๋๋ก UI๋ฅผ ๊ตฌํํ ์ ์๋ค. ์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด ํ์ ๊ณ์ธต ๋ชจ๋์๊ฒ opacity๊ฐ ๋ค์ด๊ฐ ๊ฒฝ์ฐ ๊ฐ์ฅ ์์ ๊ณ์ธต์์ ํ ๋ฒ๋ง opacity๋ฅผ ์ ์ธํด๋ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ๋๋ค. ์ ์ฝ๋๊ฐ ํจ์ํ๋ ๋ฐ๋ ๋์ด์ ํ์ ๋ทฐ๋ค์ ์์์ ๊ณตํต์ ์ธ ์์๋ค์ ์ ๊ฒฝ์ฐ์ง ์๊ณ ์ค์ง ์์ ์ด ๊ทธ๋ฆด ๋ทฐ์ ์ญํ ์๋ง ์ง์คํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
Prefer smaller, single-purpose views
Build larger views using composition
ํ์ง๋ง modifier ๋ฅผ ๋ฃ์ ๋ ์ฃผ์ํ ์ ์ด ์๋ค. ๊ธฐ๋ณธ์ ์ ๋น๋ํจํด์ ์ฌ์ฉํด์ ๊ณ์ฐ ํ Viewํ์ ์ ๋ฆฌํดํ๊ณ ๋ฆฌํดํ View๋ฅผ ๋ ๊ฐ์ ธ๋ค modify ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์์์ ์ํฅ์ ๋ฐ๋๋ค. ์ ์ฝ๋์์ ์ ์ ์๋ฏ์ด ๋ฐฑ๊ทธ๋ผ์ด๋๋ฅผ ๋จผ์ ๋ฃ๊ณ ํจ๋ฉ์ ์ฃผ๋๋, ํจ๋ฉ์ ๋จผ์ ์ฃผ๊ณ ๋ฐฑ๊ทธ๋ผ์ด๋๋ฅผ ๋ฃ๋๋์ ๋ฐ๋ผ ๋ทฐ๊ฐ ๋ค๋ฅด๊ฒ ๋ํ๋๋ค.
Primitive View
UIKit์ UIView๋ Class๋ก ์ฐธ์กฐํ์ ์ด๊ธฐ ๋๋ฌธ์ ์์์ ๊ฐ๋ ์ ์ฌ์ฉํด์ ๋ทฐ๋ฅผ ๊ทธ๋ฆฐ๋ค.
๋ฐ๋ฉด SwiftUI๋ Struct๋ก ๊ฐํ์ ์ด๊ธฐ ๋๋ฌธ์ ๊ฐ Primitive View์ Modifier๋ ์๋ก์ด ๋ทฐ๋ฅผ ๊ทธ๋ ค๋ธ๋ค.
์ด๋ Primitive View์ Modifer๋ ๊ทธ์ View Protocol์ ์ฑํํ๊ธฐ๋ง ํ๋ฉด๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์๋ก์ด View๋ฅผ ์ด๋ป๊ฒ ๊ทธ๋ ค๋ด๋์ง ๋ณด๊ธฐ์ํด์ View ํ๋กํ ์ฝ์ ๋ค์ฌ๋ค๋ณผ ํ์๊ฐ ์๋ค.
๋ทฐ ํ๋กํ ์ฝ์ ํตํด atomic building block ์ ๋ง๋ ๋ค . ๋ด๋ถ๋ฅผ ํ์ธํด๋ณด๋ฉด ํ์ ๋ณ์นญ์ ์ฌ์ฉํ์ ๋ฟ ์ฌ์ค์ ๋ทฐ์์ ๋ทฐ๋ฅผ ๋ง๋ค์ด ๊ณ์ธต๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ธ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฐ ์๊ฐ๋ ๋ค ์ ์๋ค. ๋ทฐ ํ๋กํ ์ฝ์ ์ฑํํ๋ฉด ๊ณ์ํด์ ๋ทฐ์ ๋ทฐ์ ๋ทฐ์ ๋ทฐ์... ๋ฌดํํ ์ฌ๊ท๊ฐ ๋๋ ๊ฒ์ ์๋๊ฐ? ๋ฌดํํ ์ฌ๊ท๋ฅผ ๋๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฐ์ฅ ์์ฌ์ด ๋ฐฉ๋ฒ์ ํน์ ๋ถ๋ถ์์ ๋์ด์ฃผ๋ ๊ฒ์ด๋ค. ์ด ์ญํ ์ Primitive View๊ฐ ์ํํ๋ค.
@frozen public struct VStack<Content> : View where Content : View {
@inlinable public init(
alignment: HorizontalAlignment = .center,
spacing: CGFloat? = nil,
@ViewBuilder content: () -> Content
)
public typealias Body = Never
}
Primitive View์ Body๋ Never ๋ก ์ ์ธ๋์ด ์๋ค. ๋ฐ๋ผ์ Primitive View๋ฅผ ์์ ํ๋ Modifier์์๋ ๊ณ์ํด์ some View๋ฅผ ๋ฆฌํดํ์ง๋ง ๋ง์ง๋ง modifer ๊ฐ ์คํ๋๊ณ ๋ค์ primitive View์ body๋ก ์์ Never๊ฐ ํ ๋น๋์ด ์ด๋ฌํ ์ฌ๊ท๋ฅผ ๋์ ์ ์๋ค.
Never ํ์ ์ด๋?
Never ๋ ํ๋ก๊ทธ๋จ์ ์ข ๋ฃํ๊ณ ์ ์์ ์ธ ์ ์ดํ๋ฆ์ด ๋์ด์ ์กด์ฌํ์ง ์์์ ๋ํ๋ธ๋ค
fatalError๊ฐ Neverํ์ ์ ๋ํ์ ์ธ ์์์ด๋ค.
์ฐธ๊ณ ๋งํฌ
WWDC 19 SwiftUI Essential: https://developer.apple.com/videos/play/wwdc2019/216/
What Are Result Builders?: https://www.youtube.com/watch?v=ZdK5B-tp2qE
์ทจ์ค์์ ์ํ ์ค์ํํธ UI ์ฑ๋ง๋ค๊ธฐ ์ปจํ ์ด๋๋ทฐ: https://www.youtube.com/watch?v=7ZOzChjyk8Y
'๐ฆ Flutter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Combine | 2. Operators and Subjects (0) | 2024.05.07 |
---|---|
ViewController์ ์๋ช ์ฃผ๊ธฐ (0) | 2024.05.06 |
| Combine | 1. Getting Started (0) | 2024.05.05 |
UserDefaults ๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ์ฒด์ Codable ์ ์ฑํํ ์ด์ (0) | 2024.05.05 |
| WWDC 19 | Introducing SwiftUI - Building Your First App (0) | 2024.04.23 |