λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍎 iOS/WWDC

[WWDC19] Data Flow Through SwiftUI - Part 1

by Danna 2022. 8. 30.
728x90
728x90

Principles of Data Flow

Tools for Data Flow

  • SwiftUI μ—μ„œ μ†Œκ°œλ˜λŠ” Property, BindableObject,@Environment , @Binding ,@State
    • 미리 μŠ€ν¬ν•˜μžλ©΄ BindableObject -> ObservableObject 둜 이름이 변경됨
  • 이번 μ˜μƒμ„ ν†΅ν•΄μ„œ ν•΄λ‹Ή νˆ΄λ“€μ΄ μ–΄λ–»κ²Œ, μ–Έμ œ μ“°μ΄λŠ”μ§€ μ•Œκ²Œ 될 것이닀!

 

Principle

SwiftUI 데이터 ν”Œλ‘œμš°λ₯Ό λ””μžμΈν•˜κΈ° μœ„ν•œ λ‘κ°œμ˜ 원리λ₯Ό μ•Œμ•„λ³΄μž.

 

First principle "Data Access as a Dependency"

  • 토글을 μƒκ°ν•΄λ³΄μž. ν† κΈ€ λ·°λ₯Ό 그리기 μœ„ν•΄μ„œλŠ” Bool νƒ€μž…μ˜ 데이터가 ν•„μš”ν•˜κ³ , 데이터가 μƒˆλ‘œμš΄ κ°’μœΌλ‘œ 변경될 λ•Œλ§ˆλ‹€ λ·°λ₯Ό λ³€κ²½ν•΄μ€˜μ•Ό ν•œλ‹€.
  • 데이터가 변경될 λ•Œλ§ˆλ‹€ λ·°λ₯Ό λ³€κ²½ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ„œλ‘œ μ˜μ‘΄μ„ κ°–κ²Œν•˜λŠ” λ³΅μž‘ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ•Όλ§Œ ν•œλ‹€. 
  • SwiftUI λ₯Ό μ‚¬μš©ν•˜λ©΄ 뷰와 데이터간 μ˜μ‘΄μ„±μ„ μ‰½κ²Œ ν‘œν˜„ν•  수 있고, ν”„λ ˆμž„μ›Œν¬μ—μ„œ λ™μž‘μ„ κ΅¬ν˜„λ˜μ–΄ 있기 λ•Œλ¬Έμ— κ°œλ°œμžλŠ” μœ μ €μ˜ κ²½ν—˜μ—λ§Œ μ§‘μ€‘ν•˜λ©΄ λœλ‹€.

 

Second priciple "Source of Truth"

  • 같은 λ·°λ₯Ό 그릴 λ•Œ ν•„μš”ν•œ 데이터가 μ—¬λŸ¬κ°œμ˜ μ†ŒμŠ€μ—μ„œ μ˜¨λ‹€λ©΄ 데이터가 꼬이게 되고 버그λ₯Ό λ§Œλ“€κΈ° 쉽닀.
  • μ΅œμƒμœ„ λ·°μ—μ„œ ν•˜μœ„μ˜ λ·°λ₯Ό 그리기 μœ„ν•œ 데이터λ₯Ό κ°–κ³  있고, ν•΄λ‹Ή 데이터λ₯Ό λ·°μ—κ²Œ μ „λ‹¬ν•˜λ©΄ λ‘κ°œμ˜ 뷰간에 데이터 싱크가 맞게 λœλ‹€.
  • Binding 을 μ΄μš©ν•œλ‹€λ©΄ ν•˜λ‚˜μ˜ 데이터λ₯Ό μ—¬λŸ¬κ°œμ˜ μžμ‹λ·°λ‘œ 전달해 같은 λ°μ΄ν„°μ˜ μ›μ²œμ„ 바라보도둝 ν•  수 μžˆλ‹€.

Example

SwiftUI View λŠ” immutable ν•˜κΈ° λ•Œλ¬Έμ—, 일반적인 λ³€μˆ˜μ˜ 값을 λ³€κ²½ν•  수 μ—†λ‹€.

@State property wrapper λ₯Ό λΆ™μ—¬μ€ŒμœΌλ‘œμ¨ ν•΄λ‹Ή λ³€μˆ˜λŠ” λ·°μ—μ„œ μ˜μ‘΄ν•΄μ„œ 값이 변경될 λ•Œλ§ˆλ‹€ λ·°λ₯Ό λ³€κ²½ν•˜λ„λ‘ ν•˜λŠ”κ²Œ κ°€λŠ₯함을 보여쀀닀. ν”„λ‘œνΌν‹° 래퍼λ₯Ό λΆ™μ΄λŠ” 것이 μ‹œμŠ€ν…œμ—κ²Œ ν•΄λ‹Ή λ³€μˆ˜λŠ” μ‹œκ°„μ΄ 지남에 따라 값이 λ³€κ²½λ˜κ³  λ·°μ—μ„œ ν•΄λ‹Ή λ³€μˆ˜μ— μ˜μ‘΄ν•¨μ„ μ•Œλ €μ£ΌλŠ” 것이닀.

 

μœ μ €κ°€ λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ @State λ³€μˆ˜μ˜ 값이 λ³€κ²½λ˜κ³ , ν”„λ ˆμž„μ›Œν¬λŠ” 뷰에 λŒ€ν•œ μƒˆλ‘œμš΄ λ°”λ””λ₯Ό λ§Œλ“€μ–΄λ‚Έλ‹€.

 

Property Wrapper

Swift 5.1 μ—μ„œ λ“±μž₯ν•œ κΈ°λŠ₯으둜, λ³€μˆ˜λ₯Ό λž˜ν•‘ν•΄μ„œ 값을 μ½κ±°λ‚˜ μ“Έ λ•Œ νŠΉμ •ν•œ λ™μž‘μ„ ν•  수 있게 ν•΄μ€€λ‹€. @State 도 property wrapper 의 일쒅이닀.

 

@State property wrapper λ₯Ό 뢙이면 μ–΄λ–€ λ™μž‘μ΄ μžˆλŠ”κ±ΈκΉŒ?

 

@State λ₯Ό μ‚¬μš©ν•˜λ©΄ SwiftUI ν”„λ ˆμž„μ›Œν¬λŠ” μš°λ¦¬κ°€ κ°–κ³  μžˆλŠ” λ·°μ—μ„œ λ³€μˆ˜λ₯Ό μœ„ν•œ 영ꡬ μ €μž₯μ†Œ(persistent storage)λ₯Ό ν• λ‹Ήν•˜κ³ , μ’…μ†μ μœΌλ‘œ μΆ”μ ν•œλ‹€. 그리고 λ™μΌν•œ 뷰의 μ—¬λŸ¬ μ—…λ°μ΄νŠΈμ—μ„œ μŠ€ν† λ¦¬μ§€λ₯Ό μœ μ§€ν•΄μ•Ό ν•œλ‹€λŠ” 것을 μ•Œκ³  있게 λœλ‹€.

 

일반적으둜 @State property λŠ” λͺ…μ‹œμ μœΌλ‘œ private 을 ν‘œκΈ°ν•΄μ„œ state κ°€ ν•΄λ‹Ή 뷰에 μ˜ν•΄ μ†Œμœ λ˜κ³  κ΄€λ¦¬λœλ‹€λŠ” κ±Έ λ‚˜νƒ€λ‚Έλ‹€.

 

Anatomy of an Update

 

μœ μ €κ°€ μ‹€μ œλ‘œ λ²„νŠΌμ„ λˆ„λ₯Ό λ•Œ μ–΄λ–€ λ™μž‘λ“€μ΄ μΌμ–΄λ‚ κΉŒ?

  • μœ μ €κ°€ Button 을 λˆ„λ₯΄λ©΄ @State λ³€μˆ˜μΈ isPlaying 의 값이 λ³€κ²½λœλ‹€.
  • PlayerView 의 @State λ³€μˆ˜μ΄λ―€λ‘œ ν•΄λ‹Ή λ·°λ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ”λ°,
  • ν•΄λ‹Ή 뷰와 ν•˜μœ„μ˜ λ·°λ“€, 즉 λ·° 계측을 μ „λΆ€ μƒˆλ‘œ λ§Œλ“ λ‹€.

μ—¬κΈ°μ„œ μ€‘μš”ν•œ 점은 λͺ¨λ“  @State λŠ” λ°μ΄ν„°μ˜ μ›μ²œμ΄κ³ , View λŠ” event 에 λŒ€ν•œ μ‹œν€€μŠ€κ°€ μ•„λ‹Œ state 에 λŒ€ν•œ ν•¨μˆ˜λΌλŠ” 점이닀.

Every @State is a source of truth
Views are a function of state, not of a sequence of events

 

User interaction and SwiftUI

μœ μ € μΈν„°λ ‰μ…˜κ³Ό SwiftUI μ—μ„œ μƒˆλ‘œμš΄ λ·°λ₯Ό κ·Έλ¦¬λŠ” 흐름을 λ‚˜νƒ€λ‚Έ 그림이닀. μœ μ €μ˜ μƒν˜Έμž‘μš©μœΌλ‘œ μ•‘μ…˜μ΄ λ°œμƒν•˜κ³ , μ•‘μ…˜μœΌλ‘œ State 에 변경이 μΌμ–΄λ‚˜κ³ , View λ₯Ό μƒˆλ‘œ λ§Œλ“€κ³ , μƒˆλ‘œ λ§Œλ“  View λ₯Ό μœ μ €μ—κ²Œ 보여쀀닀. 

 

🚧 Code Refactoring

μ΅œμƒμœ„ λ·° PlayerView μ—μ„œ PlayButton 을 λ”°λ‘œ λΆ„λ¦¬ν•΄λ³΄μž.

 

μš°μ„ , PlayButton λ‚΄μ—μ„œλŠ” @State λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μ•ˆλœλ‹€.

λ°μ΄ν„°μ˜ μ›μ²œμ„ λ‹€λ₯Έκ²ƒμœΌλ‘œ λ‘˜ 수 μ—†κ³ , ν•΄λ‹Ή λ·°λŠ” μž¬μ‚¬μš©λ˜λŠ” 뷰이기 λ•Œλ¬Έμ— λ°μ΄ν„°μ˜ μ›μ²œμ„ κ°€μ§ˆ 수 μ—†λ‹€. λΆ€λͺ¨λ·°μΈ PlayerView 의 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ„œ 같은 λ°μ΄ν„°μ˜ μ›μ²œμ„ 바라봐야 ν•œλ‹€.

 

PlayButton λ‚΄μ—μ„œλŠ” @Binding property wrapper λ₯Ό μ‚¬μš©ν•΄ 데이터λ₯Ό λ‚˜νƒ€λ‚΄μž.

Binding λ³€μˆ˜λŠ” μ΄ˆκΈ°κ°’μ„ 갖지 μ•Šκ³ , νƒ€μž…λ§Œ μ§€μ •ν•œλ‹€.

 

State λ³€μˆ˜μ— λ‹¬λŸ¬ ν‘œμ‹œλ₯Ό λΆ™μ—¬μ„œ PlayButton 에 전달해쀀닀.

$ λ‹¬λŸ¬ ν‘œμ‹œλŠ” property wrapper 의 λ˜λ‹€λ₯Έ κΈ°λŠ₯이닀. $ λ₯Ό λΆ™μ—¬ State λ³€μˆ˜λ₯Ό binding λ³€μˆ˜λ‘œ μ „λ‹¬ν•œλ‹€.

 

πŸ˜‡ UIKit vs SwiftUI 

UIKit μ—μ„œλŠ” ViewController μ—μ„œ λ²„νŠΌμ˜ νƒ€κ²Ÿ μ•‘μ…˜μ„ μ„€μ •ν•˜κ±°λ‚˜, delegate λ₯Ό μ •μ˜ν•΄μ„œ 데이터λ₯Ό μ „λ‹¬ν•˜λŠ” μž‘μ—…μ„ μ „λΆ€ μˆ˜ν–‰ν–ˆκΈ° λ•Œλ¬Έμ— ν—€λΉ„ν•΄μ‘Œλ‹€.

 

κ°œλ°œμžκ°€ 직접 μ„€μ •ν•΄μ€˜μ•Όν–ˆλ˜ 뷰와 λ·° μ‚¬μ΄μ˜ 데이터 싱크 λ§žμΆ”κΈ° 등을 이제 SwiftUI μ—μ„œ λ‹΄λ‹Ήν•΄μ£ΌκΈ° λ•Œλ¬Έμ—, ViewController λŠ” 더이상 μ‚¬μš©ν•  ν•„μš”κ°€ μ—†λ‹€ πŸ˜‡πŸ‘πŸ‘

 

 

Toggle, TextField, Slider λͺ¨λ‘ μƒμ„±μžμ—μ„œ Binding λ³€μˆ˜λ₯Ό 받도둝 λ˜μ–΄μžˆλ‹€. SwiftUI ν”„λ ˆμž„μ›Œν¬μ—μ„œ sourth of truth λ₯Ό 보μž₯해주기에 λ” 이상 데이터λ₯Ό λ³΅μ‚¬ν•΄μ„œ μ „λ‹¬ν•˜κ±°λ‚˜, λ°μ΄ν„°μ˜ 싱크λ₯Ό 맞좜 ν•„μš”κ°€ μ—†λ‹€.

728x90
728x90