Github.com/agelessman/…
We all know that the design concept of SwiftUI is Data flow, that is, View is driven by Data. We call the Data that View depends on state. Therefore, Data management in SwiftUI is state management.
Common state management consists of the following:
AppStorage
Binding
Environment
EnvironmentObject
FetchRequest
ObservedObject
State
StateObject
In development, their usage can be summarized in the following diagram:
If the View depends on the data, it will refresh when the data changes. We’ll focus on object object and StateObject.
ObservedObject
class MyViewModel: ObservableObject {
@Published var name: String = "Zhang"
}
struct ContentView: View {
@ObservedObject var dataModel: MyViewModel
var body: some View {
Text(dataModel.name)
}
}
Copy the code
The above code is the most common use, dataModel provides data for the ContentView, so what about @observedobject? Look at the definition:
@propertyWrapper @frozen public struct ObservedObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {
@dynamicMemberLookup @frozen public struct Wrapper {
public subscript<Subject> (dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType.Subject>) -> Binding<Subject> { get}}public init(initialValue: ObjectType)
public init(wrappedValue: ObjectType)
public var wrappedValue: ObjectType
public var projectedValue: ObservedObject<ObjectType>.Wrapper { get}}Copy the code
By analyzing the above code, we found the following important information:
ObjectType : ObservableObject
The type that represents it must be implementedObservableObject
The protocol, which we’ll talk about laterprojectedValue: ObservedObject<ObjectType>.Wrapper
That means we can use it$dataModel
To access thisprojectedValue
, its return value isWrapper
Type, look up herestruct Wrapper
The definition of it is a@dynamicMemberLookup
.@dynamicMemberLookup
And we’ll talk more about that later, but you just need to know that when we want aBind
Type of data is, you can do thisTextField(" Enter text ", text: $datamodel.name)
ObservableObject is the ObservableObject protocol.
public protocol ObservableObject : AnyObject {
/// The type of publisher that emits before the object has changed.
associatedtype ObjectWillChangePublisher : Publisher = ObservableObjectPublisher where Self.ObjectWillChangePublisher.Failure = = Never
/// A publisher that emits before the object has changed.
var objectWillChange: Self.ObjectWillChangePublisher { get}}extension ObservableObject where Self.ObjectWillChangePublisher= =ObservableObjectPublisher {
/// A publisher that emits before the object has changed.
public var objectWillChange: ObservableObjectPublisher { get}}Copy the code
ObservableObject is derived from AnyObject, which means that the implementation of the protocol must be of class type, not struct type.
This protocol requires that an objectWillChange property be returned, which must implement the Publisher protocol, which the ObservableObject extension in the code above already implements, It returns the type of ObservableObjectPublisher, we’ll look at the definition of it:
final public class ObservableObjectPublisher : Publisher {
/// The kind of values published by this publisher.
public typealias Output = Void
/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = Never
/// Creates an observable object publisher instance.
public init(a)
final public func receive<S> (subscriber: S) where S : Subscriber.S.Failure = = ObservableObjectPublisher.Failure.S.Input = = ObservableObjectPublisher.Output
final public func send(a)
}
Copy the code
Can see ObservableObjectPublisher Publisher is a very common, it is a custom Publisher, foreign only exposes a the send method, is used to signal the data is changed, the Publisher will not be any output data.
So far, we’ve seen that as long as it’s implementedObservableObject
Agreement, you get oneobjectWillChange
It’s a Publisher, just call itObjectwillchange.send () triggers a View refresh
.
Let’s implement this protocol first, the code is as follows:
class MyViewModel: ObservableObject {
@Published var name: String = "Zhang"
var age: Int = 20
func click(a) {
age = 30
objectWillChange.send()
}
}
Copy the code
If we wrap an attribute with @published, objectwillchange.send () is automatically called when the value of the attribute changes, otherwise we need to call it manually.
Let’s look again at the definition of @published:
@propertyWrapper public struct Published<Value> {
public init(wrappedValue: Value)
public init(initialValue: Value)
/// A publisher for properties marked with the `@Published` attribute.
public struct Publisher : Publisher {
/// The kind of values published by this publisher.
public typealias Output = Value
/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = Never
public func receive<S> (subscriber: S) where Value = = S.Input.S : Subscriber.S.Failure = = Published<Value>.Publisher.Failure
}
public var projectedValue: Published<Value>.Publisher { mutating get set}}Copy the code
Just remember that its project Value is a Publisher, and to get the project value, use the $sign, because it is a Publisher, so we can use Combine as we please:
$name
.map {
"The name is:\ [$0)"
}
.sink(receiveValue: {
print($0)})Copy the code
StateObject
Both @stateObject and @ObServedobject are used to wrap properties that implement the ObservableObject protocol, the only difference being the management of the property’s lifecycle.
@StateObject
Is managed by the View and is initialized once and destroyed when the View destroys it@ObservedObject
The life cycle is managed manually by us, usually from father to child
conclusion
This paper does not explain all state management in SwiftUI in detail, but only states related to Combine. Among them, the most core is ObservableObject protocol, which is absolutely the most commonly used technology in real development. In our customized View Model, By combining a series of Piplines to manipulate data, when the Source for Truth data changes, the View automatically refreshes.
Kean. Blog/post/swiftu…
[stackoverflow.com/questions/5…