Skip to content

Latest commit

ย 

History

History
368 lines (241 loc) ยท 12.9 KB

concept.md

File metadata and controls

368 lines (241 loc) ยท 12.9 KB

SwiftUI ๊ธฐ๋ณธ ๊ฐœ๋…

Index

SwiftUI์˜ ๋“ฑ์žฅ

macOS์™€ iOS์˜ ๊ฐœ๋ฐœ์— ์‚ฌ์šฉ๋˜๋Š” UI Framework๋Š” ๋ชจ๋‘ Objective-C ๊ธฐ๋ฐ˜์˜ Framework์ด๋‹ค.

ํ•˜์ง€๋งŒ Objective-C๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ ๊ฐ€์ง„ ๋Šฅ๋ ฅ์ด ๋ถ€์กฑํ•˜๊ณ , ๋ฌธ๋ฒ• ๋˜ํ•œ ์ƒ์‚ฐ์„ฑ์ด ๋–จ์–ด์กŒ๋‹ค.

์ด์— Apple์€ 2014๋…„ Swift ์–ธ์–ด๋ฅผ ์„ ๋ณด์˜€๊ณ , ๊ณ„์†ํ•ด์„œ ๋น ๋ฅธ์†๋„๋กœ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ๋‹ค.

์ถ”๊ฐ€๋กœ Swift 5.0, 5.1์—์„œ๋Š” ABI Stablity, ๋ชจ๋“ˆ ์•ˆ์ •์„ฑ์„ ์ง€์›ํ•˜๋ฉด์„œ ์•ˆ์ •์„ฑ๋„ ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ๋‹ค.

iOS UI๋ฅผ ์œ„ํ•œ UIKit์€ Objective-C ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ ์žˆ์–ด, Swift ์–ธ์–ด๋กœ ์ž‘์„ฑํ•˜์—ฌ๋„ @objc ์†์„ฑ์„ ๋ช…์‹œํ•œ๋‹ค๋˜๊ฐ€ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•œ ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…์ด ํ•„์š”ํ–ˆ๋‹ค.

button.addTarget(self, action: #selector(anyfunc), for: .touchUpInside)

@objc
func anyfunc() {
...
}

๋”ฐ๋ผ์„œ Swift ์–ธ์–ด ๊ธฐ๋ฐ˜์˜ UI Framework๊ฐ€ ํ•„์š”ํ–ˆ๊ณ , ๊ทธ๋ ‡๊ฒŒ ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ ๊ฒƒ์ด SwiftUI์ด๋‹ค.

SwiftUI๋Š” Swift ์–ธ์–ด ๊ธฐ๋ฐ˜์ด๋ฉฐ Swift์˜ ๋ชจ๋“  ํŠน์„ฑ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ ค ํ•˜๊ณ ์žˆ๋‹ค.

macOS๋ฅผ ์œ„ํ•œ UIFramework๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š”๊ฒƒ์ด ์•„๋‹Œ SwiftUI๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์กŒ๋‹ค.

Android์˜ Jetpack Compose์™€ ๋น„์Šทํ•˜๋‹ค

SwiftUI์˜ ํŠน์„ฑ

Less Code

UIKit์„ ์‚ฌ์šฉํ•ด UI๋ฅผ ๊ฐœ๋ฐœํ• ๋•Œ๋Š” ๋ทฐ ๊ฐฑ์‹ , ํ˜„์ง€ํ™”, ์ ์‘ํ˜• ๋ ˆ์ด์•„์›ƒ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์ง€๋งŒ, SwiftUI์—์„œ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด๋ถ€์—์„œ ๋Œ€๋ถ€๋ถ„ ์ง€์›ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ UIKit์œผ๋กœ ์ž‘์„ฑํ• ๋•Œ ๋ณด๋‹ค ์ƒ๋‹นํžˆ ์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“ค๊ฒŒ๋˜๊ณ , ์ฝ์–ด์•ผํ•  ์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“œ๋‹ˆ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ์—๋„ ๋„์›€์ด๋œ๋‹ค.

์„ ์–ธํ˜•

๊ธฐ์กด UIKit์˜ ๋ช…๋ นํ˜•(Imperative) ๋Œ€์‹  ์„ ์–ธํ˜•(Declarative)ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์„ ํ™œ์šฉ.

UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹, ๋ ˆ์ด์•„์›ƒ์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์ž‘์„ฑํ–ˆ๋˜ UIKit์˜ ๋ฐฉ์‹๊ณผ ๋‹ค๋ฅด๊ฒŒ ์–ด๋–ป๊ฒŒ ๋ ˆ์ด์•„์›ƒ์„ ์‹œํ‚ฌ๊ฒƒ์ด๋ฉฐ ์–ด๋–ค ํฐํŠธ๋ฅผ ์ ์šฉํ• ์ง€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ด๋ ‡๊ฒŒ๋˜๋ฉด ์ตœ์ข… UI์˜ ํ˜•ํƒœ๋ฅผ ๋ง๋กœ ์ „๋‹ฌํ•˜๋“ฏ์ด ํ‘œํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค.

Preview

Xcode11๋ถ€ํ„ฐ SwiftUI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋Œ€์‹  preview์—์„œ UI๋ฅผ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ฌผ๋ก  UIKit์—์„œ๋„ Preview๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ ๋นŒ๋“œ์— 3~5์ดˆ ์ด์ƒ ์†Œ์š”๋œ๋‹ค๋ฉด preview๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

preview์—๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ฆ‰๊ฐ์ ์œผ๋กœ ๋ฐ˜์˜๋˜๋ฉฐ ๋‹คํฌ๋ชจ๋“œ, ํ˜„์ง€ํ™”, ํฐํŠธ ๋“ฑ์„ ์—ฌ๋Ÿฌ ๋””๋ฐ”์ด์Šค ํ™˜๊ฒฝ์—์„œ ํ™•์ธํ•˜๋Š”๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค

Cross Platform

UIKit์œผ๋กœ iOS, watchOS, tvOS ๋“ฑ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์˜ UI๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ๋œ๋‹ค๋ฉด ํ•ด๋‹น OS ์— ๋งž๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กญ๊ฒŒ UI๋ฅผ ๊ตฌ์„ฑํ•ด์•ผํ–ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ SwiftUI๋Š” ์ƒ๋‹น ๋ถ€๋ถ„์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์˜ ์•ฑ์„ ๋” ์‰ฝ๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค.

SwiftUI์˜ 4๊ฐ€์ง€ ์›์น™

์„ ์–ธํ˜•

SwiftUI๋Š” ์„ ์–ธํ˜• ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ ‘๋ชฉํ•˜์˜€๋‹ค. ์„ ์–ธํ˜•๊ณผ ๋ช…๋ นํ˜•์˜ ์ฐจ์ด๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค

  • ๋ช…๋ นํ˜•์€ ์–ด๋–ป๊ฒŒ(HOW) ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์ดˆ์ฒจ์„ ๋งž์ถ”๊ณ ์žˆ๋‹ค.
    • ๋ช…๋ น์„ ์˜ฌ๋ฐ”๋ฅธ ์ˆœ์„œ๋กœ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์—†๋‹ค.
  • ์„ ์–ธํ˜•์€ ๋ฌด์—‡์„(WHAT) ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์ดˆ์ฒจ์„ ๋งž์ถ”๊ณ ์žˆ๋‹ค.
    • ๋ช…๋ น์„ ๋‹ค๋ฃจ๋Š”๋Œ€์‹  ํ”„๋กœ๊ทธ๋žจ์ด ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” ๋ชฉ์  ์ž์ฒด๋ฅผ ์„ค๋ช…ํ•œ๋‹ค.

์ž๋™ํ™”

๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์ด ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ๋” ์„ค๊ณ„๋˜์–ด์žˆ๋‹ค.

AutoLayout์„ ์œ„ํ•œ ๋งŽ์€ ์ฝ”๋“œ๋“ค์ด ์ œ๊ฑฐ๋˜์—ˆ๊ณ , ์ตœ์†Œํ•œ์˜ ์„ค๋ช…๋งŒ์œผ๋กœ UI๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

์กฐํ•ฉ

SwfitUI API๋Š” ๋ทฐ์˜ ์กฐํ•ฉ๊ณผ ๋ถ„๋ฆฌ๋ฅผ ๊ฐ„๋‹จํžˆ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณตํ•œ๋‹ค.

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

๋˜ protocol์— ๋‹ค์–‘ํ•œ modifier๋ฅผ ์ง€์›ํ•ด protocol์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ชจ๋“  ๊ฐ์ฒด์—๊ฒŒ ๋™์ผํ•œ UI๋‚˜ ๊ธฐ๋Šฅ์„ ์†์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ผ๊ด€์„ฑ

UI๋Š” ํ•ญ์ƒ ๋ฐ์ดํ„ฐ์™€ ๋™๊ธฐํ™” ๋˜์–ด์•ผ ํ•œ๋‹ค.

UIKit์—์„œ๋Š” ๋ฐ์ดํ„ฐ์™€ UI๋ฅผ ๋™๊ธฐํ™” ํ•˜๊ธฐ์œ„ํ•ด ์ˆ˜๋™์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๊ณ ,

์—ฌ๋Ÿฌ ๊ธฐ์ˆ ๋“ค์ด ์‚ฌ์šฉ๋˜์–ด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ๋„ ๋งŽ์•„์กŒ๋‹ค.

SwiftUI์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ์ฆ‰์‹œ UI๋„ ์ž๋™์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด Source Of Truth๋ผ๋Š” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜๊ฒŒ๋˜๋Š”๋ฐ ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์— ๋”ฐ๋ผ UI๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š”๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ์™€ UI๋ฅผ ๋™๊ธฐํ™” ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ํ•ญ์ƒ ์ผ๊ด€์„ฑ ์žˆ๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.


Opaque Type(๋ถˆํˆฌ๋ช…ํƒ€์ž…)

Swift UI์˜ body ์— ์‚ฌ์šฉ๋˜๋Š” some ์ด Opaque Type์— ๊ด€๋ จ๋œ ํ‚ค์›Œ๋“œ์ด๋ฉฐ, property, function๋“ฑ return ํƒ€์ž…์— ํ•œ์ •์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

ํƒ€์ž… ์ •๋ณด ์€๋‹‰

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

์ด๋ ‡๋“ฏ ๋ทฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค body์˜ ํƒ€์ž…์„ ์ƒˆ๋กœ ์ง€์ •ํ•˜๊ธฐ์—๋Š” ๋ฌด๋ฆฌ๊ฐ€ ์žˆ์–ด some ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ค ํƒ€์ž…์ธ์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ˆจ๊ธฐ๊ณ , ์ฑ„ํƒํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‚จ๊ธด ์ฑ„ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์ด๋กœ์ธํ•ด API๋Š” ์ถ”์ƒํ™” ๋˜๊ณ  ๋ชจ๋“ˆ๊ฐ„ ๊ฒฐํ•ฉ๋„๋Š” ๋‚ฎ์•„์ง€๊ฒŒ ๋œ๋‹ค.

๋ถˆํˆฌ๋ช… ํƒ€์ž…์€ ํŠน์ • ํƒ€์ž…์— ๋Œ€ํ•œ ์ œ์•ฝ์กฐ๊ฑด์„ ์ง€์ •ํ•˜์—ฌ ํ™•์žฅ์„ฑ์„ ๋†’์ด๋Š” ์ œ๋„ค๋ฆญ๊ณผ ๋ฐ˜๋Œ€๋˜๋Š” ๊ฐœ๋…์ด๋‹ค.

ํƒ€์ž… ์ถ”์ƒํ™”

์ œ๋„ค๋ฆญ์€ caller ์ธก์—์„œ callee์˜ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•˜์ง€๋งŒ

๋ถˆํˆฌ๋ช…ํƒ€์ž…์€ callee๊ฐ€ caller์˜ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•œ๋‹ค.

// Generic
func genericFunction<T: Animal>(_ animal: T) { ... } // callee๋Š” ํƒ€์ž…์„ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค
genericFunction(Dog()) // caller๊ฐ€ ์ „๋‹ฌํ•  ํƒ€์ž…์„ ๊ฒฐ์ •
genericFunction(Cat()) 

// Opaque Type
func opaqueTypeFunction() -> some Animal { Dog() } // callee๊ฐ€ ํƒ€์ž…์„ ๊ฒฐ์ •(Dog)
let someAnimal: some Animal = opaqueTypeFunction() // caller๋Š” ์ถ”์ƒํ™”๋œ ํƒ€์ž…์„ ์ „๋‹ฌ๋ฐ›์Œ(some Animal)

์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ

์ œ๋„ค๋ฆญ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ์—์„œ๋งŒ ํƒ€์ž…์„ ์ˆจ๊ธฐ๊ณ  ๋Ÿฐํƒ€์ž„์—์„œ๋Š” ๋…ธ์ถœ๋œ๋‹ค.

๋ถˆํˆฌ๋ช…ํƒ€์ž… ์—ญ์‹œ ๋Ÿฐํƒ€์ž„์—์„œ ํƒ€์ž…์ด ๋…ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜ #1 Line ์€ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ์ผ์–ด๋‚œ๋‹ค.

protocol Animal { }

struct Dog: Animal {
    var color: UIColor { UIColor.brown }
}

let dog: some Animal = Dog()
dog.color  // #1
(dog as! Dog).color

ํƒ€์ž… ์ •์ฒด์„ฑ

๊ธฐ์กด์—๋Š” ํ”„๋กœํ† ์ฝœ์„ ๋ฐ˜ํ™˜ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ์–ด๋–ค ํƒ€์ž…์ด๋“  ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์ด ์žฅ์ ์ด์˜€๋‹ค. ํ•˜์ง€๋งŒ ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์ด ๋ฐ˜ํ™˜ ๋  ์ˆ˜ ์žˆ๋Š” ์ ์—์„œ ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์žƒ๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

protocol Animal {}

struct Dog: Animal {}
struct Cat: Animal {}

func returnType() -> Animal {
	.random() ? Dog() : Cat()
}

let animal: Animal = returnType() // Cat? Dog?

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

protocol P {}

struct SomeType: P {}

func nested<T: P>(_ param: T) -> P {
	param
}

let foo: P = nested(SomeType()) // foo๋Š” P ํƒ€์ž…์ด๋ฏ€๋กœ, protocol P๋ฅผ ๋งŒ์กฑ ํ•  ์ˆ˜ ์—†์Œ
let bar = nested(foo)

๋˜ํ•œ Self ํƒ€์ž… ๋˜๋Š” associatedtype ํƒ€์ž…์ด ์„ ์–ธ๋œ ํ”„๋กœํ† ์ฝœ์€ ํƒ€์ž…์„ ๋ช…์‹œํ•˜๊ฑฐ๋‚˜ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹ค์Œ ์ฝ”๋“œ๋“ค์€ ๋ชจ๋‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

func someFunction(_ lhs: Equatable, _ rhs: Equatable) -> Bool {} // Equatable์€ Self ํƒ€์ž… ์ž…๋‹ˆ๋‹ค.

func someFunction() -> Hashable {} // Hashable์€ Equatable์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ Self ํƒ€์ž… ์ž…๋‹ˆ๋‹ค.

var someProperty: Collection {} // Collection์€ associatedtype ํƒ€์ž…์ด ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํ† ์ฝœ์€ ์œ ์—ฐํ•œ ํƒ€์ž…์ด ์žฅ์ ์ด์ง€๋งŒ ์ด๋กœ ์ธํ•ด ๋ถˆํ™•์‹คํ•œ ๋ถ€๋ถ„์ด ์กด์žฌํ•˜๋ฉฐ, ๋ถˆํˆฌ๋ช… ํƒ€์ž…์€ ์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•œ ๋‘๊ฐ€์ง€ ๋ฐฉ์•ˆ์„ ๊ฐ•์ œํ•œ๋‹ค.

์‹ค์ฒดํƒ€์ž…

๋ถˆํˆฌ๋ช… ํƒ€์ž…์€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ ์‹ค์ฒด ํƒ€์ž…์ด์—ฌ์•ผ ํ•œ๋‹ค.

protocol Animal {}

struct Dog: Animal {}
struct Cat: Animal {}

func returnConcreteType() -> some Animal {
    let result: Animal = Dog()
    return result
}

์œ„ ์ฝ”๋“œ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉฐ ์‹ค์ฒด ํƒ€์ž…์ด ์•„๋‹Œ Animal ํ”„๋กœํ† ์ฝœ์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋ฐœ์ƒํ•œ๋‹ค.

๋”ฐ๋ผ์„œ result์˜ ํƒ€์ž…์„ ์‹ค์ฒดํƒ€์ž…์ธ Dog๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค.

ํ”„๋กœํ† ์ฝœ์ด ์•„๋‹Œ ์‹ค์ฒดํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•˜๋Š”๊ฒƒ์€ ๋‘๋ฒˆ์งธ ๋ฐฉ์•ˆ์ธ ์–ธ์ œ๋‚˜ ๋™์ผํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š”๊ฒƒ์„ ์ง€ํ‚ค๋ ค๋Š” ๊ฒƒ์ด๊ธฐ๋„ ํ•˜๋‹ค.

๋™์ผํƒ€์ž…

๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์€ ๋‹ฌ๋ผ๋„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ ๋™์ผํ•ด์•ผํ•œ๋‹ค.

Self ํƒ€์ž…์ด๋‚˜ associatedtype์„ ๊ฐ€์ง„ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ œ๋„ค๋ฆญ์ด ํ•„์š”ํ•˜๋‹ค.

๋‹ค์Œ์ฝ”๋“œ์˜ ํ•จ์ˆ˜์—์„œ ์ œ๋„ค๋ฆญ ๋งค๊ฐœ๋ณ€์ˆ˜ T๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณณ์—์„œ ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ,

lhs์™€ rhs๋ผ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๊ฐ’์ด ๋‹ค๋ฅด๋”๋ผ๋„ ๋™์ผํ•œ ํƒ€์ž…์„ ๊ฐ–๋Š”๋‹ค.

func genericFunction<T: Equatable>(_ lhs: T, _ rhs: T) -> Bool {
    lhs == rhs
}

let gf1 = genericFunction("Swift", "UI") // ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํƒ€์ž… ์ •๋ณด ์ œ๊ณต
let gf2 = genericFunction(true, false)
let gf3 = genericFunction("Swift", true) // ํƒ€์ž…์ด ๋ถˆ์ผ ์น˜ ํ•  ๊ฒฝ์šฐ ์—๋Ÿฌ Conflicting arguments to generic parameter 'T' ('Bool' vs. 'String')

print(gf1)
print(gf2)

/*
	false
	false
*/

์•ž์„œ ๋ถˆํˆฌ๋ช… ํƒ€์ž…์€ ์ œ๋„ค๋ฆญ์„ ๋ฐ˜๋Œ€๋กœ ์ ์šฉํ•œ ๊ฐœ๋…์ด๋ผ๊ณ  ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ๋™์ผํ•˜๊ฒŒ ๋ฐ˜๋Œ€๋กœ ์ ์šฉ๋œ๋‹ค.

Self ํƒ€์ž…์ด๋‚˜ aasociatedtype์€ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์— ๋Œ€ํ•œ ํƒ€์ž…์ด ๋˜๋ฉฐ, ๊ฐ’์€ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋”๋ผ๋„ ํƒ€์ž…์€ ํ•ญ์ƒ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค.

func stringOpaqueTypeFunction() -> some Equatable {
    .random() ? "Swift" : "UI" // ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํƒ€์ž… ์ •๋ณด ์ œ๊ณต
}

func boolOpaqueTypeFunction() -> some Equatable {
    .random() ? true : false
}

func strangeOpaqueTypeFunction() -> some Equatable {
    .random() ? "Swift" : true // Result values in '? :' expression have mismatching types 'String' and 'Bool'
}

let sotf1 = stringOpaqueTypeFunction()
let sotf2 = boolOpaqueTypeFunction()

print(sotf1)
print(sotf2)

/*
    Swift
    true
*/

๋”ฐ๋ผ์„œ SwftUI์˜ body ํ•จ์ˆ˜์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

var body: some View {
    .random() ? Rectangle() : Circle() // Result values in '? :' expression have mismatching types 'Rectangle' and 'Circle'
}

์ •๋ฆฌ

  • ๋ถˆํˆฌ๋ช… ํƒ€์ž…(Opaque Type)์€ ์ž์„ธํ•œ ํƒ€์ž…๊ณผ ๊ตฌํ˜„์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ˆจ๊ธฐ๊ณ  ํŠน์ • protocol์„ ๋”ฐ๋ฅด๋Š” API ๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•œ๋‹ค.
  • prtocol ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด์„œ ํƒ€์ž…์— ๋Œ€ํ•œ ์ •์ฒด์„ฑ์„ ๋ณด์žฅํ•˜์—ฌ API ๋‚ด๋ถ€์—์„œ ํƒ€์ž… ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์„ ํ™œ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • some ํ‚ค์›Œ๋“œ๋Š” property, index, ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์—๋งŒ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, some ํ‚ค์›Œ๋“œ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    • protocol
    • class
    • Any
    • AnyObject

Omit Return(๋ฆฌํ„ด ์ƒ๋žต)

๋ฆฌํ„ด ์ƒ๋žต์€ ๋‹จ์ผ ํ‘œํ˜„์‹(single-expression)์ด ์ž‘์„ฑ๋œ ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ๋Š” return ํ‚ค์›Œ๋“œ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ‘œํ˜„์‹(expression)์ด๋ž€ ์‹คํ–‰์‹œ์— ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ side effect๋ฅผ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜, ๋‘˜ ๋‹ค ๋ฐœ์ƒํ•˜๊ฒŒ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋งํ•˜๋ฉฐ Swift์—์„œ๋Š” prefix, infix, primary, postfix 4๊ฐ€์ง€์˜ ํ‘œํ˜„์‹์ด ์กด์žฌํ•œ๋‹ค.

์ƒ์„ธ๋‚ด์šฉ์€ ๋ฌธ์„œ ์ฐธ๊ณ 

let add = { (a: Int, b: Int) in
	a+b
}

func add(x: Int, y: Int) -> Int {
	x+y
}

์ค‘์š”ํ•œ์ ์€ ๋‹จ์ผ ํ‘œํ˜„์‹๊ณผ ๋‹จ์ผ ํ–‰์€ ๋‹ค๋ฅด๋‹ค๋Š” ์ ์ด๋‹ค.

var body: some View {
	Text("title")
}

var body: some View {
	Text("title")
		.font(.title)
}

์•„๋ž˜์˜ body๋Š” ๋‘๊ฐœ์˜ ํ–‰์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ์ง€๋งŒ, ๋‹จ์ผ ํ‘œํ˜„์‹์ด๋ฏ€๋กœ return ํ‚ค์›Œ๋“œ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

if-else ๊ตฌ๋ฌธ์€ ์‚ผํ•ญ์—ฐ์‚ฐ์ž์™€ ๊ฐ™์€ ์—ญํ• ์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‹ค์ˆ˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ,

๊ตฌ๋ฌธ๊ณผ ํ‘œํ˜„์‹์˜ ์ฐจ์ด๋ผ๋Š”๊ฒƒ์„ ์•Œ์•„๋‘์ž

// ์ปดํŒŒ์ผ ์„ฑ๊ณต
var body: some View {
	true ? Text("์„ฑ๊ณต") : Text("์‹คํŒจ")	
}

// ์ปดํŒŒ์ผ ์˜ค๋ฅ˜
var body: some View {
	if true {
		Text("์„ฑ๊ณต")
	else { 
		Text("์‹คํŒจ")
	}	
}

// ์ปดํŒŒ์ผ ์„ฑ๊ณต
var body: some View {
	if true {
		return Text("์„ฑ๊ณต")
	else { 
		return Text("์‹คํŒจ")
	}	
}