SlideShare ist ein Scribd-Unternehmen logo
1 von 27
Downloaden Sie, um offline zu lesen
Ton Attapong, iOS Developer at Seven Peaks Software
SwiftUI
Property wrapper and How to use them with MVVM in SwiftUI
Topic
• Property wrapper
s

• Property wrappers in SwiftU
I

• MVVM in SwiftUI
Property wrappers in SwiftUI
• @Stat
e

• @Bindin
g

• @ObservedObjec
t

• @Publishe
d

• @EnvironmentObjec
t

• Etc
What is property wrappers?
A property wrapper adds a layer of separation between code that manages how a
property is stored and the code that defines a property. For example, if you have
properties that provide thread-safety checks or store their underlying data in a database,
you have to write that code on every property. When you use a property wrapper, you
write the management code once when you define the wrapper, and then reuse that
management code by applying it to multiple properties
.

https://docs.swift.org/swift-book/LanguageGuide/Properties.html
Example
import Foundation


struct AppSettings {


// Normal way


static shared = AppSettings()


var appLanguage: String {


get { UserDefaults.standard.value(forKey: "app_language") as? String ?? "" }


set { UserDefaults.standard.set(newValue, forKey: “app_language") }


}


var isLoggedIn: String {


get { UserDefaults.standard.value(forKey: "is_logged_in") as? Bool ?? false }


set { UserDefaults.standard.set(newValue, forKey: "is_logged_in") }


}


// Property wrapper


@PropertyWrapperUserDefault(key: "app_language", defaultValue: "") static var _appLanguage: String


@PropertyWrapperUserDefault(key: "is_logged_in", defaultValue: false) static var _isLoggedIn: Bool


}


// How to access


AppSettings.shared.appLanguage = "en"


AppSettings._appLanguage = “en"
How to create
import Foundation


@propertyWrapper


struct PropertyWrapperUserDefault<T> {


private var key : String


private var defaultValue: T


init(key: String, defaultValue: T) {


self.key = key


self.defaultValue = defaultValue


}


var wrappedValue: T {


get { UserDefaults.standard.value(forKey: key) as? T ?? defaultValue }


set { UserDefaults.standard.set(newValue, forKey: key) }


}


}
Example 2
Validate Phone number property wrappe
r

`ProjectedValue
`

Condition
s

- Phone number should have 10 character
s

- We can check it is true or false by access projectedValue



Example 2
import Foundation


@propertyWrapper struct PhoneNumberValidation {


var projectedValue: Bool = false


var storedValue: String = ""


init(wrappedValue: String) {


self.wrappedValue = wrappedValue


}


var wrappedValue: String {


get { storedValue }


set {


projectedValue = newValue.count == 10 ? true : false


storedValue = newValue.count < 10 ? newValue : String(newValue.prefix(10))


}


}


}
Example 2
struct Phone {


@PhoneNumberValidation var phoneNumber: String


func printPhoneNumber() {


print(phoneNumber)


print($phoneNumber)


}


}


let phone = Phone(phoneNumber: “1234”)


phone.printPhoneNumber()


// Result


1234


false
@State
A property wrapper type that can read and write a value managed by SwiftUI
.

SwiftUI manages the storage of any property you declare as a state. When the state
value changes, the view invalidates its appearance and recomputes the body. Use the
state as the single source of truth for a given vie
w

https://developer.apple.com/documentation/swiftui/state
@State
struct ContentView: View {

@State private var counter: Int = 0

var body: some View {

VStack {

Text("Counter: (counter)")

Button("Hit me", action: {

counter += 1

})

}.padding(16)

}

}
SwiftUI View Lifecycle
3 Phases
 

- Appearing
 

- Updatin
g

- Disappearing
Appearing
Initializer
Subscribe

to state
body Render View

(Text, Button)
onAppear


(Text, Button)
Updating
Initializer
Subscribe

to state
body Render View

(Text, Button)
onAppear


(Text, Button)
Disappearing
Initializer
Subscribe

to state
body Render View

(Text, Button)
onAppear


(Text, Button)
onDisAppear


(Text, Button)
ProjectedValue of @State
/// A binding to the state value.


/// Use the projected value to pass a binding value down a view hierarchy.


/// To get the `projectedValue`, prefix the property variable with `$`


public var projectedValue: Binding<Value> { get }
@Binding
A property wrapper type that can read and write a value owned by a source of truth
.

Use a binding to create a two-way connection between a property that stores data, and
a view that displays and changes the data. A binding connects a property to a source of
truth stored elsewher
e

https://developer.apple.com/documentation/swiftui/binding
@Binding
struct ContentView: View {

@State private var randomNumber: Int = 0

var body: some View {

Text("1st horse number is: (randomNumber)")

CustomView(randomNumber: $randomNumber)

}

}

struct CustomView: View {

@Binding var randomNumber: Int

var body: some View {

Button("Hit me") {

self.randomNumber = Int.random(in: 1...100)

}

}

}
@Published
A type that publishes a property marked with an attribute
.

Publishing a property with the @Published attribute creates a publisher of this type. You
access the publisher with the $ operato
r

https://developer.apple.com/documentation/combine/published
@Published
class SomeObservable: ObservableObject {

@Published var userName: String = ""

init() {

userName = "Ton"

}

}
@ObservedObject
A property wrapper type that subscribes to an observable object and invalidates a view
whenever the observable object changes
.

https://developer.apple.com/documentation/swiftui/observedobject
@ObservedObject
struct ContentView: View {

@ObservedObject var someObservable = SomeObservable()

var body: some View {

Text("Hello, (someObservable.userName)!”)

.padding()

}

}
@Published @ObservedObject
struct ContentView: View {

@ObservedObject var someObservable = SomeObservable()

var body: some View {

Text("Hello, (someObservable.userName)!")

.padding()

}

}

class SomeObservable: ObservableObject {

@Published var userName: String = ""

init() {

userName = “Ton"

}

}
@EnvironmentObject
A property wrapper type for an observable object supplied by a parent or ancestor view
.

An environment object invalidates the current view whenever the observable object
changes. If you declare a property as an environment object, be sure to set a
corresponding model object on an ancestor view by calling its environmentObject(_:)
modifier
.

https://developer.apple.com/documentation/swiftui/environmentobject
@EnvironmentObject
class UserSettings: ObservableObject {

@Published var userName = "Ton"

}

@main

struct EnvironmentObjectApp: App {

let userSettings = UserSettings()

var body: some Scene {

WindowGroup {

ContentView().environmentObject(userSettings)

}

}

}

struct ContentView: View {

@EnvironmentObject var userSettings: UserSettings

var body: some View {

Text("Hello, (userSettings.userName)")

.padding()

}

}
@EnvironmentObject VS @ObservedObject
- shared across many view
s

- update any views
 

View1 -> View2 -> View3 -> View
4
Let’s create a Project
MVVM with all property wrappers that I’ve talked about
.

- Display data from ViewModel to View (@Published, @ObservedObject
)

- Pass data between views (@Binding
)

- Update our view (@State
)

- Share data in our app (@EnvironmentObject)

Weitere ähnliche Inhalte

Ähnlich wie Property wrapper and how to use them with mvvm in swift ui i copy

Attached property
Attached propertyAttached property
Attached property
msarangam
 
Practical AngularJS
Practical AngularJSPractical AngularJS
Practical AngularJS
Wei Ru
 

Ähnlich wie Property wrapper and how to use them with mvvm in swift ui i copy (20)

JavaScript Misunderstood
JavaScript MisunderstoodJavaScript Misunderstood
JavaScript Misunderstood
 
Attached property
Attached propertyAttached property
Attached property
 
A tour through Swift attributes
A tour through Swift attributesA tour through Swift attributes
A tour through Swift attributes
 
eXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction TrainingeXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction Training
 
Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
 
Json
JsonJson
Json
 
Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
 
Lab #2: Introduction to Javascript
Lab #2: Introduction to JavascriptLab #2: Introduction to Javascript
Lab #2: Introduction to Javascript
 
Javascript Templating
Javascript TemplatingJavascript Templating
Javascript Templating
 
iOS
iOSiOS
iOS
 
Practical AngularJS
Practical AngularJSPractical AngularJS
Practical AngularJS
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
Analyzing source code of WPF examples by the Infragistics Company
Analyzing source code of WPF examples by the Infragistics CompanyAnalyzing source code of WPF examples by the Infragistics Company
Analyzing source code of WPF examples by the Infragistics Company
 
Metaprogramming in JavaScript
Metaprogramming in JavaScriptMetaprogramming in JavaScript
Metaprogramming in JavaScript
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
 
SwiftUI - Performance and Memory Management
SwiftUI - Performance and Memory ManagementSwiftUI - Performance and Memory Management
SwiftUI - Performance and Memory Management
 
Oojs 1.1
Oojs 1.1Oojs 1.1
Oojs 1.1
 
JS basics
JS basicsJS basics
JS basics
 
Angular.js Primer in Aalto University
Angular.js Primer in Aalto UniversityAngular.js Primer in Aalto University
Angular.js Primer in Aalto University
 
JSAnkara Swift v React Native
JSAnkara Swift v React NativeJSAnkara Swift v React Native
JSAnkara Swift v React Native
 

Property wrapper and how to use them with mvvm in swift ui i copy

  • 1. Ton Attapong, iOS Developer at Seven Peaks Software SwiftUI Property wrapper and How to use them with MVVM in SwiftUI
  • 2. Topic • Property wrapper s • Property wrappers in SwiftU I • MVVM in SwiftUI
  • 3. Property wrappers in SwiftUI • @Stat e • @Bindin g • @ObservedObjec t • @Publishe d • @EnvironmentObjec t • Etc
  • 4. What is property wrappers? A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property. For example, if you have properties that provide thread-safety checks or store their underlying data in a database, you have to write that code on every property. When you use a property wrapper, you write the management code once when you define the wrapper, and then reuse that management code by applying it to multiple properties . https://docs.swift.org/swift-book/LanguageGuide/Properties.html
  • 5. Example import Foundation struct AppSettings { // Normal way static shared = AppSettings() var appLanguage: String { get { UserDefaults.standard.value(forKey: "app_language") as? String ?? "" } set { UserDefaults.standard.set(newValue, forKey: “app_language") } } var isLoggedIn: String { get { UserDefaults.standard.value(forKey: "is_logged_in") as? Bool ?? false } set { UserDefaults.standard.set(newValue, forKey: "is_logged_in") } } // Property wrapper @PropertyWrapperUserDefault(key: "app_language", defaultValue: "") static var _appLanguage: String @PropertyWrapperUserDefault(key: "is_logged_in", defaultValue: false) static var _isLoggedIn: Bool } // How to access AppSettings.shared.appLanguage = "en" AppSettings._appLanguage = “en"
  • 6. How to create import Foundation @propertyWrapper struct PropertyWrapperUserDefault<T> { private var key : String private var defaultValue: T init(key: String, defaultValue: T) { self.key = key self.defaultValue = defaultValue } var wrappedValue: T { get { UserDefaults.standard.value(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) } } }
  • 7. Example 2 Validate Phone number property wrappe r `ProjectedValue ` Condition s - Phone number should have 10 character s - We can check it is true or false by access projectedValue
 

  • 8. Example 2 import Foundation @propertyWrapper struct PhoneNumberValidation { var projectedValue: Bool = false var storedValue: String = "" init(wrappedValue: String) { self.wrappedValue = wrappedValue } var wrappedValue: String { get { storedValue } set { projectedValue = newValue.count == 10 ? true : false storedValue = newValue.count < 10 ? newValue : String(newValue.prefix(10)) } } }
  • 9. Example 2 struct Phone { @PhoneNumberValidation var phoneNumber: String func printPhoneNumber() { print(phoneNumber) print($phoneNumber) } } let phone = Phone(phoneNumber: “1234”) phone.printPhoneNumber() // Result 1234 false
  • 10. @State A property wrapper type that can read and write a value managed by SwiftUI . SwiftUI manages the storage of any property you declare as a state. When the state value changes, the view invalidates its appearance and recomputes the body. Use the state as the single source of truth for a given vie w https://developer.apple.com/documentation/swiftui/state
  • 11. @State struct ContentView: View { @State private var counter: Int = 0 var body: some View { VStack { Text("Counter: (counter)") Button("Hit me", action: { counter += 1 }) }.padding(16) } }
  • 12. SwiftUI View Lifecycle 3 Phases - Appearing - Updatin g - Disappearing
  • 13. Appearing Initializer Subscribe
 to state body Render View
 (Text, Button) onAppear 
 (Text, Button)
  • 14. Updating Initializer Subscribe
 to state body Render View
 (Text, Button) onAppear 
 (Text, Button)
  • 15. Disappearing Initializer Subscribe
 to state body Render View
 (Text, Button) onAppear 
 (Text, Button) onDisAppear 
 (Text, Button)
  • 16. ProjectedValue of @State /// A binding to the state value. /// Use the projected value to pass a binding value down a view hierarchy. /// To get the `projectedValue`, prefix the property variable with `$` public var projectedValue: Binding<Value> { get }
  • 17. @Binding A property wrapper type that can read and write a value owned by a source of truth . Use a binding to create a two-way connection between a property that stores data, and a view that displays and changes the data. A binding connects a property to a source of truth stored elsewher e https://developer.apple.com/documentation/swiftui/binding
  • 18. @Binding struct ContentView: View { @State private var randomNumber: Int = 0 var body: some View { Text("1st horse number is: (randomNumber)") CustomView(randomNumber: $randomNumber) } } struct CustomView: View { @Binding var randomNumber: Int var body: some View { Button("Hit me") { self.randomNumber = Int.random(in: 1...100) } } }
  • 19. @Published A type that publishes a property marked with an attribute . Publishing a property with the @Published attribute creates a publisher of this type. You access the publisher with the $ operato r https://developer.apple.com/documentation/combine/published
  • 20. @Published class SomeObservable: ObservableObject { @Published var userName: String = "" init() { userName = "Ton" } }
  • 21. @ObservedObject A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes . https://developer.apple.com/documentation/swiftui/observedobject
  • 22. @ObservedObject struct ContentView: View { @ObservedObject var someObservable = SomeObservable() var body: some View { Text("Hello, (someObservable.userName)!”) .padding() } }
  • 23. @Published @ObservedObject struct ContentView: View { @ObservedObject var someObservable = SomeObservable() var body: some View { Text("Hello, (someObservable.userName)!") .padding() } } class SomeObservable: ObservableObject { @Published var userName: String = "" init() { userName = “Ton" } }
  • 24. @EnvironmentObject A property wrapper type for an observable object supplied by a parent or ancestor view . An environment object invalidates the current view whenever the observable object changes. If you declare a property as an environment object, be sure to set a corresponding model object on an ancestor view by calling its environmentObject(_:) modifier . https://developer.apple.com/documentation/swiftui/environmentobject
  • 25. @EnvironmentObject class UserSettings: ObservableObject { @Published var userName = "Ton" } @main struct EnvironmentObjectApp: App { let userSettings = UserSettings() var body: some Scene { WindowGroup { ContentView().environmentObject(userSettings) } } } struct ContentView: View { @EnvironmentObject var userSettings: UserSettings var body: some View { Text("Hello, (userSettings.userName)") .padding() } }
  • 26. @EnvironmentObject VS @ObservedObject - shared across many view s - update any views View1 -> View2 -> View3 -> View 4
  • 27. Let’s create a Project MVVM with all property wrappers that I’ve talked about . - Display data from ViewModel to View (@Published, @ObservedObject ) - Pass data between views (@Binding ) - Update our view (@State ) - Share data in our app (@EnvironmentObject)